【发布时间】:2020-02-06 01:13:57
【问题描述】:
当一个类有一个未定义移动操作的成员时,我很难理解隐式移动操作:
int main() {
struct A // no move: move = copy
{
A() = default;
A(const A&) {
cout << "A'copy-ctor\n";
};
A& operator=(const A&) {
cout << "A'copy-assign\n";
return *this;
}
};
struct B
{
B() = default;
A a; // does this make B non-moveable?
unique_ptr<int> upi;
// B(B&&) noexcept = default;
// B& operator=(B&&)noexcept = default;
};
A a;
A a2 = std::move(a); // ok use copy ctor instead of move one
a2 = std::move(a); // ok use copy assignment instead of move one
B b;
B b2 = std::move(b); // why this works?
b = std::move(b2); // and this works?
// b = b2; // error: copy deleted because of non-copyable member upi
cout << "\nDone!\n";
}
所以我看到A是一个不可移动的类,因为它的复制控制操作的定义所以它只能被复制并且任何试图移动这个类的对象的尝试,都使用相应的复制操作来代替.
到这里为止,如果我是正确的就可以了。但是B 有一个不可复制的对象upi,它是一个unique_ptr,因此复制操作被定义为删除的函数,所以我们不能复制这个类的对象。但是这个类有一个不可移动的对象a,因此我认为这个类(B)既不能复制也不能移动。但是为什么b2 的初始化和b 的赋值工作正常呢?究竟发生了什么?
B b2 = std::move(b); // ok?!
为什么上面的行调用了类A的复制构造函数,它调用了B的移动构造函数?
- 对我来说情况变得更糟:如果我取消注释
B中的移动操作行,上面的初始化将无法编译并抱怨引用已删除的函数,赋值也是如此!
谁能帮我看看到底发生了什么?在将问题发布到此处之前,我已经在 cppreference 和许多网站上进行了谷歌搜索和阅读。
输出:
A'copy-ctor
A'copy-assign
A'copy-ctor
A'copy-assign
Done!
【问题讨论】:
-
通常,复制构造函数或复制赋值运算符采用
T const&,它可以绑定到所有表达式(左值和右值)。所以这是一个可行的候选函数,如果没有竞争的移动函数,它将默认赢得重载决议
标签: c++ c++11 copy-constructor move-constructor implicit-methods