Rvalue references
In earlier programming languages, assignment was in the following form:
<variable> := <expression>
However, in C it is possible to write
*++p = ++*q;
<expression> = <expression>
therefore it was need to make difference left-value (lvalue) and right value
(rvalue).
In C++03
non-const references can bind to lvalues
const references can bind to lvalues or rvalues.
but there is nothing to bind to
non-const rvalues
to protect temporaries.
void incr(int& a) { ++a; }
int i = 7;
const int ci = 10;
incr(i);
incr(ci);
incr(11);
It makes certain operations (much) more expensive
template <class Expensive>
void swap( Expensive& a, Expensive& b)
{
T temp(a);
a = b;
b = tmp;
}
template <class T>
class vector
{
vector( const vector& );
vector( vector&& );
vector& operator=( const vector& );
vector& operator=( vector&& );
}
The move constructor and move assignment can and usually do modify
their arguments. They are destructive.
An rvalue reference (&&) can bind to an rvalue but not to an lvalue.
T a;
T f();
T& r1 = a;
T& r2 = f();
T&& rr1 = f();
T&& rr2 = a;
The swap example:
template <class Expensive>
void swap( Expensive& a, Expensive& b)
{
T temp = move(a);
a = move(b);
b = move(tmp);
}
move(x) means "take x as an rvalue".
Called move() for historical reasons, it would be better tzo called rval()
The move(x) is a template and can be written in C++11 using rvalue references.
template <class T>
typename remove_reference<T>::type&& move(T&& a)
{
return a;
}
In C++11 all containers have move operations (copy constr and operator=)
and the insert new elements operations have overloaded versions taking rvalue.
For POD-style data, copy may be the most efficient.
There are movable but non-copyable types:
fstream
unique_ptr (non-shared, con-copyable)
std::thread
ifstream myfile("myfile.txt");
ifstream current_file = myfile;
std::vector<unique_ptr<Base>> v1, v2;
v1.push_back(unique_ptr<Base>(new Derived()));
v2 = v1;
v2 = move(v1);
Performance
http:
copy constructor: 66.3
return auto_ptr: 5.6
move constructor: 4.5