A move constructor allows the resources owned by an rvalue object to be moved into an lvalue without creating its copy.
An rvalue is an expression that does not have any memory address, and an lvalue is an expression with a memory address.
Before jumping on to the rvalue reference, let’s see one of the limitations in C++:
int &j = 20;
The above code snippet will give an error because, in C++, a variable cannot be referenced to a temporary object. The correct way to do it is to create an rvalue reference using &&
:
int &&j = 20;
Temporary objects are often created during the execution of a C++ program.
The best usage of an rvalue reference can be seen in the move constructor.
#include <iostream>#include <vector>using namespace std;class A{int *ptr;public:A(){// Default constructorcout << "Calling Default constructor\n";ptr = new int ;}A( const A & obj){// Copy Constructor// copy of object is createdthis->ptr = new int;// Deep copyingcout << "Calling Copy constructor\n";}~A(){// Destructorcout << "Calling Destructor\n";delete ptr;}};int main() {vector <A> vec;vec.push_back(A());return 0;}
Now, when the above code is executed, the default constructor is called at the time that the temporary object A is created. The copy constructor is called as the temporary object of A is pushed back in the vector.
In the above code, there is a serious performance overhead as the temporary object A is first created in the default constructor and then in the copy constructor. The move constructor is used to avoid this performance overhead:
#include <iostream>#include <vector>using namespace std;class A{int *ptr;public:A(){// Default constructorcout << "Calling Default constructor\n";ptr = new int ;}A( const A & obj){// Copy Constructor// copy of object is createdthis->ptr = new int;// Deep copyingcout << "Calling Copy constructor\n";}A ( A && obj){// Move constructor// It will simply shift the resources,// without creating a copy.cout << "Calling Move constructor\n";this->ptr = obj.ptr;obj.ptr = NULL;}~A(){// Destructorcout << "Calling Destructor\n";delete ptr;}};int main() {vector <A> vec;vec.push_back(A());return 0;}
When the above code is executed, the move constructor is called instead of the copy constructor. With the move constructor, the copy of the temporary object of A is avoided. For a large number of push_back
statements, using the move constructor is an efficient choice.
Note: a move constructor can be explicitly called, with the
move()
function, for already created objects.