【问题标题】:Move constructor is automatic generated even a member doesn't have a move constructor?即使成员没有移动构造函数,移动构造函数也会自动生成?
【发布时间】:2017-06-21 17:58:14
【问题描述】:

引自C++ Primer

如果我们明确要求编译器通过 使用= default,编译器无法移动所有 成员,则移动操作将被定义为删除

移动构造函数被定义为删除如果 类有一个成员,它定义了自己的复制构造函数,但也没有 定义一个移动构造函数,或者如果该类有一个没有定义它的成员 自己的复制操作,编译器无法合成移动 构造函数

有些代码似乎违反了这条规则:

#include <utility>
#include <iostream>

struct X {
    X() = default;
    X(const X&) { std::cout << "X(const X&)" << std::endl; }
    int i;
};

struct hasX {
    hasX() = default;
    hasX(const hasX &) = delete;
    hasX(hasX &&) = default;
    X mem;
};


int main()
{
    hasX hx, hx2 = std::move(hx);  //output is X(const X&)
}

X 没有定义移动构造函数,编译器无法为它合成一个。

根据上面的规则,hasX的移动构造函数被删除了。

但是,因为hasX的拷贝构造函数被删除了,hx2 = std::move(hx)必须调用移动构造函数输出"X(const X&amp;)",这说明hasX的移动构造函数已经定义,它使用X的拷贝构造函数移动”。这似乎违反了上面的规则。

那么,是不是在 C++ 标准中定义或只是一个编译器实现?

我测试的编译器:VS2015 和a online compiler

感谢您的帮助!

【问题讨论】:

    标签: c++ c++11 constructor


    【解决方案1】:

    你的书好像错了。 Copying is a valid move operation 所以只要成员有const type&amp; 形式的复制构造函数,所以它可以绑定到右值,移动操作将回退到一个副本。

    在你的例子中

    hasX(hasX &&) = default;
    

    可以替换为

    hasX(hasX &&rhs) : mem(std::move(rhs.mem)) {}
    

    因为这是默认的,它会编译得很好。

    【讨论】:

    • 你能给我一个标准的参考来支持这个吗?我在支持该声明时遇到了问题。在我看来,该标准另有规定(N3337 12.8/11、9/6、12.8/12)
    • @AndyG 链接到答案的所有引号都支持我的断言。还有 12.8/11 怎么让你认为它是不允许的?
    • 我发现“由于重载决议而无法复制/移动的类类型 M(或其数组)的非静态数据成员”。
    • @NathanOliver:链接答案中关于引用的部分澄清了问题,但老实说,它在我看来就像标准中存在矛盾一样。 12.8/11 声明如果X 有一个没有移动构造函数且不可轻易复制的非静态数据成员,则删除默认的移动构造函数。当然,它没有移动 ctor,因为它有一个用户提供的复制 ctor。而且它不是简单可复制的 (9/6),因为它有一个用户提供的复制 ctor (12.8/12)
    • @AndyG 是的。这是标准上的一个缺陷,并已被引用。 IIRC DR 回溯到它们所使用的标准,因此它适用于 C++11 标准。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-08
    • 2012-01-07
    • 2013-03-27
    • 2016-12-16
    • 2012-11-09
    • 2011-09-13
    相关资源
    最近更新 更多