Move Semantics and Rvalue Reference

On 2017/05/04 at 00:06

I was confused with the move semantics and the rvalue reference because I thought they are tight together to fix a single problem. However, they are two differenct ideas and rvalue reference is just a method to help implement move semantics much easier!

Rvalue reference is a lvalue which can hold a reference to a rvalue (can be thought as a temporary which can not be addressed in program). Before C++11, we can use const T& as rvalue reference but the referenced value can not be modified by the reference. In C++11, we can simple use T&& to reference the rvalue and we can use the reference to modify the rvalue.

Move semantics is meant to steal the resource held by another object to prevent unwanted copy. So in C++11, most of the stl classes have defined move constructor, move assignment to transfer(not copy) the resources from the temporary object to current object directly. Binary operators can also be benefit from the rvalue references, because the temporary values produces in the middle calculation can be used directly.

string foo("hello")
string bar("world");

// string operator+ (const string& lhs, const string& rhs);
// string operator+ (string&& lhs, const string& rhs);
// string& operator= (string&& str);
string result = foo + bar + string("!!");

// foo + bar creates a temporary which can be captured by rvalue reference
// finally, the result use move assignment to transfer the resources in the temporary object to result

std::move is an another confusing function for me in the past. Actually, it is just a cast function which can cast any value to rvalue reference.

vector<int> v1 = {1, 2, 3};
cout << v1.size();  // size=3

vector<int> v2 = move(v1);
cout << v1.size();  // size=0, because the internal data is transfer to v2 by the move assignment
cout << v2.size();  // size=3

Because move constructor and move assignment is designed to take temporary rvalue as argument, it should be safe to steal the resource from the temporary. If you use std::move on a lvalue and pass it to a move constructor and move assignment, the internal data of the lvaue should be thought as transfered. This is why the v1 in the above example is empty after moved and assigned (it depends on the implementation of the move constructor and move assignment implementation in different classes).