我有一个包含std :: vector的简单类,我想在按值返回类时从移动语义(而不是RVO)中受益。
我通过以下方式实现了移动构造函数,复制构造函数和复制赋值运算符:
class A
{
public:
// MOVE-constructor.
A(A&& other) :
data(std::move(other.data))
{
}
// COPY-constructor.
A(const A& other) :
data(other.data)
{
}
// COPY-ASSIGNMENT operator.
A& operator= (const A& other);
{
if(this != &other)
{
data = other.data;
}
return *this;
}
private:
std::vector<int> data;
};
上述实施是否正确?
还有一个问题:我是否必须实现这些成员中的任何一个,还是由编译器自动生成?我知道默认情况下会生成复制构造函数和复制赋值运算符,但编译器是否也可以自动生成移动构造函数? (我使用MSVC和GCC编译此代码。)
提前感谢任何建议。 (我知道已经存在一些类似的问题,但不适用于这种情况。)
答案 0 :(得分:5)
对于这个类[*],它们都是不必要的,因为如果你没有声明其中的任何一个,它就会有隐式的。
你的建造者很好。所以下面的代码表面上调用了移动构造函数:
A f() { return A(); }
A a = f(); // move construct (not copy construct) from the return value of f
实际上,move-elision可能会启动,在这种情况下,实际上只会调用no-args构造函数。我假设您计划提供除复制和移动之外的一些构造函数; - )
您的副本分配是正常的,它与隐式分配的不同之处仅在于它具有自我分配检查,而隐式检查不具备。我不认为我们应该讨论自我指派是否值得,这不是错误的。
您尚未定义移动赋值运算符。鉴于你定义了其他人,你应该已经完成了,但是如果你摆脱其余部分则隐含[*]。移动赋值运算符(无论是用户定义的还是隐式的)确保以下代码将移动而不是复制:
A a;
a = f();
[*]在已完成的C ++ 11实现上,到目前为止还没有。您可以根据每个编译器检查此功能是否已实现,并且可能最终会遇到一些可怕的#define
恶作剧,直到MSVC为止。
答案 1 :(得分:2)
对于这个确切的场景,您不需要声明任何移动/复制/赋值功能。编译器将生成正确的默认值。