为什么 C++ 允许您移动包含已删除移动操作的对象的 类?
Why does C++ allow you to move classes containing objects with deleted move operations?
为什么我可以在 class 上使用 std::move
,它包含已删除移动语义的类型的字段(案例 1),但不允许在此类实例上使用它class(案例 2)?
我理解案例 2。我已经明确删除了移动构造函数,所以如果我尝试移动它,就会出现错误。但我希望情况 1 也会出现这种情况,其中 class 也被移动。
class TestNonMovable {
std::string ss;
public:
TestNonMovable(){}
TestNonMovable(const TestNonMovable&) {}
TestNonMovable(TestNonMovable&&) = delete;
};
class SomeClass {
TestNonMovable tnm;
};
int main() {
// case1: This compiles, my understanding is that for SomeClass::tnm compiler will use copy constrctor
SomeClass sc1;
SomeClass sc2 = std::move(sc1);
// case2: This does not compile, move constructor is explicitly deleted, compiler will not try using copy constructor
TestNonMovable tnm;
TestNonMovable tnm2 = std::move(tnm); //error: use of deleted function 'TestNonMovable::TestNonMovable(TestNonMovable&&)'
}
注意两者的区别类。对于 TestNonMovable
(情况 2),您 显式 将移动构造函数声明为 delete
。使用 TestNonMovable tnm2 = std::move(tnm);
在重载决议中选择删除的移动构造函数,然后导致错误。
对于 SomeClass
(情况 1),您没有显式声明移动和复制构造函数。复制构造函数将被隐式声明和定义,但移动构造函数将被隐式声明和定义为删除,因为它有一个 non-movable 数据成员。 请注意 deleted implicitly declared move constructor 不会参与重载决议 。使用 SomeClass sc2 = std::move(sc1);
,复制构造函数被选中,然后代码工作正常。从 std::move
返回的右值引用也可以绑定到 lvalue-reference 到 const(即 const SomeClass&
)。
The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue). (since C++14)
顺便说一句:std::move 本身在这两种情况下都是允许的。它不执行 移动操作 ,它只是将参数转换为右值。在这两种情况下,移动操作都发生在构建过程中。
为什么我可以在 class 上使用 std::move
,它包含已删除移动语义的类型的字段(案例 1),但不允许在此类实例上使用它class(案例 2)?
我理解案例 2。我已经明确删除了移动构造函数,所以如果我尝试移动它,就会出现错误。但我希望情况 1 也会出现这种情况,其中 class 也被移动。
class TestNonMovable {
std::string ss;
public:
TestNonMovable(){}
TestNonMovable(const TestNonMovable&) {}
TestNonMovable(TestNonMovable&&) = delete;
};
class SomeClass {
TestNonMovable tnm;
};
int main() {
// case1: This compiles, my understanding is that for SomeClass::tnm compiler will use copy constrctor
SomeClass sc1;
SomeClass sc2 = std::move(sc1);
// case2: This does not compile, move constructor is explicitly deleted, compiler will not try using copy constructor
TestNonMovable tnm;
TestNonMovable tnm2 = std::move(tnm); //error: use of deleted function 'TestNonMovable::TestNonMovable(TestNonMovable&&)'
}
注意两者的区别类。对于 TestNonMovable
(情况 2),您 显式 将移动构造函数声明为 delete
。使用 TestNonMovable tnm2 = std::move(tnm);
在重载决议中选择删除的移动构造函数,然后导致错误。
对于 SomeClass
(情况 1),您没有显式声明移动和复制构造函数。复制构造函数将被隐式声明和定义,但移动构造函数将被隐式声明和定义为删除,因为它有一个 non-movable 数据成员。 请注意 deleted implicitly declared move constructor 不会参与重载决议 。使用 SomeClass sc2 = std::move(sc1);
,复制构造函数被选中,然后代码工作正常。从 std::move
返回的右值引用也可以绑定到 lvalue-reference 到 const(即 const SomeClass&
)。
The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue). (since C++14)
顺便说一句:std::move 本身在这两种情况下都是允许的。它不执行 移动操作 ,它只是将参数转换为右值。在这两种情况下,移动操作都发生在构建过程中。