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);  // ok
    incr(ci); // syntax error
    incr(11); // syntax error



It makes certain operations (much) more expensive


template <class Expensive>
void swap( Expensive& a, Expensive& b)
{
    T temp(a);  // second copy of a
    a = b;      // second copy of b
    b = tmp;    // second copy of tmp
}


template <class T>
class vector
{
    // ...
    vector( const vector& );    // usual copy constructor
    vector( vector&& );         // move constructor

    vector& operator=( const vector& ); // copy assignment
    vector& operator=( vector&& );      // move assignment
}


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;      // ok: bind to an lvalue
    T& r2 = f();    // syntax error: can't bind 

    T&& rr1 = f();  // ok: bind to a temporary
    T&& rr2 = a;    // syntax error: can't bind to lvalue


The swap example:


template <class Expensive>
void swap( Expensive& a, Expensive& b)
{
    T temp = move(a);   // no copy, but may invalidate a
    a = move(b);        // no copy, but may invalidate b
    b = move(tmp);      // no copy, but may invalidate 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;  // no copy, file handler is passed.


std::vector<unique_ptr<Base>>  v1, v2;
v1.push_back(unique_ptr<Base>(new Derived()));  // move, no copy

v2 = v1;        // syntax error: not copyable 
v2 = move(v1);  // ok: pointers are moved to v2



Performance


http://arcticinteractive.com/2008/11/29/brief-look-cpp0x-move-semantics-performance/

copy constructor:  66.3
return auto_ptr:    5.6
move constructor:   4.5