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