Modern C++ In-Depth — Move Semantics, Part 2
In our last post, we discussed the benefits of using std::move(...)
to avoid copying large containers. In this installment, we'll take a look at how we might go about defining move semantics for our own custom types, should we need them.
Terminology
Before we get too deep, let’s examine the terms lvalue and rvalue.
The first letter in these two terms derives from the observation that lvalues typically appear on the left-hand side of an assignment operator, whereas rvalues (when thought of as the temporary return values of function calls) tend to appear on the right-hand side. Since these value categories don’t always appear in the context of assignments, it may be more useful to think of an lvalue as a named object instance whose address can be taken. By extension, rvalues don’t have names and their addresses cannot be taken.
Value References
The magic that makes std::move(...)
work is a new type of reference, called an rvalue reference (first introduced in C++11). In order to declare an rvalue reference, use two ampersands instead of one.
Here is an example of this new syntax in comparison to the traditional lvalue reference syntax that we’ve seen before:
Widget& get_widget();
Widget make_widget();Widget& y = get_widget(); //< An lvalue reference.
Widget&& z = make_widget(); //< An rvalue reference.