How to: Write a Move Constructor
This topic describes how to write a move constructor and a move assignment operator for a C++ class. A move constructor enables you to implement move semantics, which can significantly improve the performance of your applications. For more information about move semantics, see Rvalue Reference Declarator: &&.
This topic builds upon the following C++ class, MemoryBlock, which manages a memory buffer.
// MemoryBlock.h #pragma once #include <iostream> #include <algorithm> class MemoryBlock { public: // Simple constructor that initializes the resource. explicit MemoryBlock(size_t length) : _length(length) , _data(new int[length]) { std::cout << "In MemoryBlock(size_t). length = " << _length << "." << std::endl; } // Destructor. ~MemoryBlock() { std::cout << "In ~MemoryBlock(). length = " << _length << "."; if (_data != NULL) { std::cout << " Deleting resource."; // Delete the resource. delete[] _data; } std::cout << std::endl; } // Copy constructor. MemoryBlock(const MemoryBlock& other) : _length(other._length) , _data(new int[other._length]) { std::cout << "In MemoryBlock(const MemoryBlock&). length = " << other._length << ". Copying resource." << std::endl; std::copy(other._data, other._data + _length, _data); } // Copy assignment operator. MemoryBlock& operator=(const MemoryBlock& other) { std::cout << "In operator=(const MemoryBlock&). length = " << other._length << ". Copying resource." << std::endl; if (this != &other) { // Free the existing resource. delete[] _data; _length = other._length; _data = new int[_length]; std::copy(other._data, other._data + _length, _data); } return *this; } // Retrieves the length of the data resource. size_t Length() const { return _length; } private: size_t _length; // The length of the resource. int* _data; // The resource. };
The following procedures describe how to write a move constructor and a move assignment operator for the example C++ class.
To create a move constructor for a C++ class
-
Define an empty constructor method that takes an rvalue reference to the class type as its parameter, as demonstrated in the following example:
MemoryBlock(MemoryBlock&& other) : _data(NULL) , _length(0) { }
2. In the move constructor, assign the class data members from the source object to the object that is being constructed:
_data = other._data;
_length = other._length;
3. Assign the data members of the source object to default values. This prevents the destructor from freeing resources (such as memory) multiple times:
other._data = NULL; other._length = 0;
To create a move assignment operator for a C++ class
1. Define an empty assignment operator that takes an rvalue reference to the class type as its parameter and returns a reference to the class type, as demonstrated in the following example:
MemoryBlock& operator=(MemoryBlock&& other) { }
2. In the move assignment operator, add a conditional statement that performs no operation if you try to assign the object to itself.
if (this != &other) { }
3. In the conditional statement, free any resources (such as memory) from the object that is being assigned to. The following example frees the _data member from the object that is being assigned to:
// Free the existing resource. delete[] _data;
Follow steps 2 and 3 in the first procedure to transfer the data members from the source object to the object that is being constructed:
// 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 = NULL; other._length = 0;
4. Return a reference to the current object, as shown in the following example:
return *this;
To prevent resource leaks, always free resources (such as memory, file handles, and sockets) in the move assignment operator.
To prevent the unrecoverable destruction of resources, properly handle self-assignment in the move assignment operator.
If you provide both a move constructor and a move assignment operator for your class, you can eliminate redundant code by writing the move constructor to call the move assignment operator. The following example shows a revised version of the move constructor that calls the move assignment operator:
// Move constructor. MemoryBlock(MemoryBlock&& other) : _data(NULL) , _length(0) { *this = std::move(other); }