Search code examples
c++c++11movemove-constructor

Best C++ move constructor implementation practice


I am trying to understand the implementation of move-constructor. We all know if we need to manage resources in a C++ class, we need to implement Rule of five (C++ programming).

Microsoft gives us an example: https://msdn.microsoft.com/en-us/library/dd293665.aspx

Here is better one, which uses copy-swap to avoid code duplication: Dynamically allocating an array of objects

     // C++11
     A(A&& src) noexcept
         : mSize(0)
         , mArray(NULL)
     {
         // Can we write src.swap(*this);
         // or (*this).swap(src);
         (*this) = std::move(src); // Implements in terms of assignment
     }

In the move-constructor, directly:

         // Can we write src.swap(*this);
         // or (*this).swap(src);

Because I think (*this) = std::move(src) is a little more complicated. Because if we write as (*this) = src inadvertently, it would call normal assignment operator instead of the move-assignment-operator.

Apart from this question, in Microsoft's example, they wrote code like this: in move-assignment-operator, do we need to check self-assignment? Is it possible to happen?

// Move assignment operator.
MemoryBlock& operator=(MemoryBlock&& other)
{
   std::cout << "In operator=(MemoryBlock&&). length = " 
             << other._length << "." << std::endl;

   if (this != &other)
   {
      // Free the existing resource.
      delete[] _data;

      // Copy the data pointer and its length from the 
      // source object.
      _data = other._data;
      _length = other._length;

      // Release the data pointer from the source object so that
      // the destructor does not free the memory multiple times.
      other._data = nullptr;
      other._length = 0;
   }
   return *this;
}

Solution

  • One way is to implement the default constructor, copy constructor and swap function.

    And then implement the move constructor, copy and move assignment operators using the first three.

    E.g.:

    struct X
    {
        X();
        X(X const&);
        void swap(X&) noexcept;
    
        X(X&& b)
            : X() // delegate to the default constructor
        {
            b.swap(*this);
        }
    
        // Note that this operator implements both copy and move assignments.
        // It accepts its argument by value, which invokes the appropriate (copy or move) constructor.
        X& operator=(X b) {
            b.swap(*this);
            return *this;
        }
    };
    

    If you have been using this idiom in C++98, then once you add the move constructor you get the move assignment without writing a single line of code.

    In some cases this idiom may be not the most efficient. Because the copy operator always first constructs a temporary and then swaps with it. By hand coding the assignment operators it may be possible to get better performance. When in doubt, check optimized assembly output and use a profiler.