2.1.10 Rvalue References

What was the problem

In the function build_widget() below, a temporary string is created by the code label + "def", then a reference to this string is passed to the constructor of widget, where it is then copied in widget::m_label. Finally, the temporary is deleted.

struct widget 
{ 
  widget(const std::string& label) 
    : m_label(label) 
  {} 
 
  std::string m_label; 
}; 
 
void build_widget() 
{ 
  std::string label("abc"); 
  widget w(label + "def"); 
}

Temporaries have the interesting property that they have no use but to be consumed by an expression building another value. In other words, in the example above, the purpose of the result of label + "def" is to end up in widget::m_label. So why do we need a copy? It would be more efficient to just pass the instance created by the concatenation directly to the final variable.

How the Problem is Solved

To solve this problem, C++11 introduces the concept of rvalue references, which are, to put it simply, references to temporaries. These references are denoted with a double ampersand &&. See the updated example, below:

struct widget 
{ 
  widget(std::string&& label) 
    : m_label(label) 
  {} 
 
  std::string m_label; 
}; 
 
void build_widget() 
{ 
  std::string label("abc"); 
  widget f(label + "def"); 
}

The signature of the constructor indicates that it accept temporaries as arguments. However, this code is not enough to avoid copies of the string yet, as the instruction m_label(label) still copies the string. The next step is to replace this instruction with m_label(std::move(label)), and then we will have no copy. This is the topic of section 2.2.

Note that if the constructor’s argument was widget, like in widget(widget&& that), then this would declare what is called a move-constructor. This is a distinct constructor than the copy-constructor and it is explicitly allowed to steal the internals of its argument, as long as the instance behind the argument stays in a valid state.