Andrew Koenig

Dr. Dobb's Bloggers

How the C++ Compiler Decides to Move Objects

July 10, 2013

After reading this post, you should be able to figure out what std::move does, although not necessarily how it does it.

Two weeks ago, I discussed rvalue references. I noted that, as its name suggests, an rvalue reference is a reference that is bound to an rvalue. More specifically, an rvalue reference can be bound only to an rvalue:

If we add const to the equation, both a plain reference and an rvalue reference can bind to an rvalue:

const int&& r5 = 3; // OK

However this binding involves adding a const to the type of 3. This addition turns out to be important for the following subtle reason:

void foo(const int&);
void foo(int&&);

Suppose we overload a function to accept a plain reference to const in one version and an rvalue reference in the other. Then whenever we call foo with an lvalue, we will get foo(const int&); whenever we call foo with an rvalue, we will get foo(int&&). The const is necessary for the plain reference because otherwise we would not be able to give foo a const int lvalue as its argument.

Inside the body of foo(const int&), its parameter is a reference to const. As usual, the argument is not copied, and the function itself cannot change the parameter's value because the parameter is const. The interesting part is what happens inside the body of foo(int&&).

Because an rvalue reference is just another kind of reference, the parameter of foo(int&&) is a reference. This reference is not a reference to const. In other words, the function is permitted to change its parameter's value, even though this value is an rvalue. For example:

void foo(int&& n) {
++n;
}

This function is permitted to increment n because n is a reference. It is permitted to do so even though we can call

foo(3);

Here, 3 is an rvalue, so n gets bound to 3 without 3 being copied. Nevertheless, the function is permitted to change the value of n. Does doing so change the value of 3? The answer is that we can't tell, because there is no way of inspecting the value of 3 later on to discover whether it changed!

We have defined a class Thing with two overloaded constructors. The first of them takes a reference to const Thing. Inside the body of this constructor, t refers directly to the object from which we want to construct our new Thing. As ever, we can use the contents of this object, but we cannot change those contents.

In the second constructor, t also refers to an object from which we are to construct a Thing. In this constructor, however, that object is known to be an rvalue — which means that we can change the contents of t without worrying about clobbering important data.

When we overload constructors in this way, we generally refer to the first one as the copy constructor and the second as the move constructor. Similarly, we can have copy-assignment and move-assignment operators as well:

For both constructors and assignment operators, the copy version is required to leave the original alone; the move version is permitted to destroy the original's value so long as the original object is left in a state that allows it to be safely destroyed.

Having seen this technique, you should now be able to figure out what std::move does, although not necessarily how it does it. Try to do so before we discuss it in detail next week.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!