我正试图围绕移动构造函数,并希望通过这个问题获得更多的见解。这是一个简单的课程。
class A
{
private:
vector<B> Bs;
public:
/*
..
*/
A(A&& other)
: Bs
{
Bs = other.Bs;
}
}
即使B
没有移动构造函数,我的移动构造函数看起来是否正确?即使我没有明确为类B
的对象编写移动赋值,移动构造函数是否仍然有效?如果不是,这是否意味着如果想要移动任何物体,他首先必须确保每个属性也是可移动的?
答案 0 :(得分:4)
如果您的对象包含可移动的对象(例如std::vector
),则默认的移动构造函数将负责移动,因此您无需执行任何操作。尝试使用Rule of Zero。
在你的情况下,不,移动ctor不会做正确的事情。它将复制,因为在
Bs = other.Bs;
other.Bs
是函数内部的左值,因为它有一个名称(是的,它指的是右值引用,但other
本身是左值)。你需要
Bs = std::move(other.Bs);
或更好
A(A&& other) : Bs(std::move(other.Bs)) {}
但是,在这种情况下,你真的不应该编写任何用户定义的移动构造函数。
强烈建议您阅读Howard Hinnant,这个人对移动语义的概念贡献最大:http://www.slideshare.net/ripplelabs/howard-hinnant-accu2014
答案 1 :(得分:3)
不,不是。你的话在这里:
var newEntry = {};
newEntry[$scope.xxxx.key] = {
name: $scope.xxx.name,
age: $scope.xxx.age,
email: $scope.xxx.email,
};
xxx.$add( newEntry );
您正在进行复制作业。在移动构造函数体中不会更改表达式值类型。左值仍然是左值,右值仍然是左值。
要进行移动分配,它看起来像这样:
Bs = other.Bs;
但它仍然没有那么高效。
还有另一个问题。您的代码未编译,因为您已为Bs = std::move(other.Bs);
构造函数提交了大括号。事实上,这是你应该移动价值的地方。这是一个例子:
std::vector
最好的解决方案是:// a kitten dies when your move constructor is not noexcept
A(A&& other) noexcept
// in the move constructor of A, we move construct it's member too.
: Bs{std::move(other.Bs)}
// empty body
{}
你是对的,它是空的。如果你没有放任何构造函数,编译器会为你做。
如果你想添加其他构造函数但让编译器添加它自己的移动构造函数,你可以显式默认它:
最后一件事。如果你的类包含另一个不可移动但可复制的类,它将尽其所能:复制构造它。
让类型// bonus: noexcept when it can.
A(A&&) = default;
成为不可移动的类但可以复制。
以下是一个例子:
C
答案 2 :(得分:1)
这里的移动构造函数将是&#34;有效的&#34;因为A
对象是由A
类型的右值构造的,所以它将被调用。它可以正常工作,创建另一个对象的有效副本。但是,它没有那么有效,因为它复制了内部std::vector
对象。这是一个性能问题,而不是正确性问题。
这里实际上有两个性能问题。第一个是构造函数默认构造B
子对象,然后分配给它。这很浪费。解决这个问题:
A::A(A&& other) : B(other.B) {
}
第二个是允许移动构造函数从另一个对象窃取。为此,实现应从B
子对象移动:
A::A(A&& other) : B(std::move(other.B)) {
}
最后,为了回答标题中的问题,std::move
适用于不可移动的类型。它所做的只是将左值转换为右值;不可移动的类型可以(通常)从rvalues复制,因此除非你处理一个非常不正常的类型,只需在对象中的几乎所有东西上使用std::move
。 (移动int值可能看起来很奇怪,但它无害)。