移动构造函数(和其他)的正确实现是什么?

时间:2013-01-08 10:05:51

标签: c++ c++11 move-semantics

我有一个包含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编译此代码。)

提前感谢任何建议。 (我知道已经存在一些类似的问题,但不适用于这种情况。)

2 个答案:

答案 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)

对于这个确切的场景,您不需要声明任何移动/复制/赋值功能。编译器将生成正确的默认值。