What is the correct implementation of move constructor (and others)?

advertisements

I have a simple class which contains an std::vector, and I would like to benefit from move semantics (not RVO) when returning the class by value.

I implemented the move constructor, copy constructor and copy assignment operators in the following way:

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;
};

Are the above implementations correct?

And an other question: do I even have to implement any of these members, or are they auto-generated by the compiler? I know that the copy-constructor and the copy-assignment operator are generated by default, but can the compiler auto-generate the move constructor as well? (I compile this code both with MSVC and GCC.)

Thanks in advance for any suggestions. (I know that there already are some similar questions, but not for this exact scenario.)


They're all unnecessary for this class[*], since it would have implicit ones if you didn't declare any of them.

Your constructors are fine. So the following code ostensibly calls the move constructor:

A f() { return A(); }
A a = f(); // move construct (not copy construct) from the return value of f

In fact move-elision might kick in, in which case only the no-args constructor is actually called. I assume you plan to provide some constructors other than copy and move ;-)

Your copy assignment is fine, it differs from the implicit one only in that it has the self-assignment check, which the implicit one would not. I don't think we should have the argument whether a self-assignment check is worth it or not, it's not incorrect.

You haven't defined a move-assignment operator. Given that you defined the others, you should have done, but if you get rid of the rest it's implicit[*]. The move assignment operator (whether user-defined or implicit) is what ensures that the following code will move instead of copying:

A a;
a = f();

[*] On a completed C++11 implementation, of which so far none exist. You can check on a per-compiler basis whether this feature is implemented yet, and probably you'll end up with some horrible #define shenanigans until MSVC does.