We have talked about references before, and explained them in detail. We have also mentioned a concept called "lvalues". An lvalue in C++ is something which can be assigned to. It persists beyond a single expression. All variables are lvalues. Rvalues, on the other hand, are temporary values which do not exist beyond the expression that uses them. Obviously, they cannot be assigned to. For example:
a + (b * c); //the value of b*c is an rvalue, a temporary value; it will be stored somewhere until it's added to a;
//after that, it won't exist anymore
However, C++11 introduced a new concept which combines rvalues with something we already know very well - the copy constructor and the assignment operator. This new feature is called move semantics. The first step in understanding move semantics is explaining rvalue references (note that this is only possible in C++11 and newer versions). As the name says, rvalue references are references to rvalues (in contrast to the references we've talked about before, which were lvalue references). Here is how you declare an rvalue reference:
But why is this important? Why would you want to use an rvalue reference? Consider the following code:
MyClass c(a + b); //a+b is an rvalue, which makes this line equal to:
MyClass c(temp); //this activates the copy constructor
We can see that the copy constructor was called. This is a common situation, and we have explained it before, when we learned how to write a copy constructor. However, in situations like this one, we do not want to perform a copy operation. A faster and more suitable alternative would be a move operation
- we just want to copy the data and then "nullify" the source, without creating a deep copy. It's okay to do this because the client has no way of inspecting the source object again anyway - since it was an rvalue.
This brings us to the following conclusion: in addition to the copy constructor, destructor and the overloaded assignment operator, we should also write the move constructor and overload the move assignment operator.
Below is an example:
/*move assignment operator*/
this->array = other->array;
other->array = nullptr;
Since we have already learned how the assigment operator is overloaded (the code is similar to that of the copy constructor), we leave it to the reader to implement the move assignment operator as an exercise.