Rvalue References in C++11

Posted: July 8, 2012 in C++
Tags: , ,

The terms Lvalue & Rvalue has been there since the days of C but still their definition as found in many literature is not very uniform.Before even discussing about the what Rvalue references are in C++11 we need some discussion to get these clarified in the first place.

Any object is nothing but a area in the memory and we need a name to access that memory area from our program. This named and accessible storage area are the objects and variables. These named objects and references are known  as the Lvalues, the name is so because they can appear in the left hand side of an assignment expression.However every Lvalue cannot appear in the left hand side of an assignment as Lvalue can also refer to a constant.So to differentiate sometimes we use the term as modifiable Lvalues.

Following are the examples of Lvalue references:

int i=10; 
string s = "Hello";  

The & reference operator we use in C++ actually a Lvalue reference. The following line of code will throw a compilation error:

string& s1 = "Hello";

error: invalid initialization of non-const reference of type ‘std::string& {aka std::basic_string<char>&}’ from an rvalue of type ‘const char*’

Here s1 is a Lvalue reference and error we are getting says that it cannot bind a Rvalue reference to a non-constant (Lvalue) reference. But before we proceed further it’s now high time to formally introduce the Rvalues. These are things whose address is (was till C++11) not accessible by the program, unnamed temporary objects. In the above example “Hello” is a Rvalue as we need to create a temporary string object for this. So it’s quite obvious that assignment/binding a of Rvalue to a Lvalue reference is failing.

In C++11 we have now Rvalue references which enables us to access these temporary unnamed objects as well. The Rvalue references are denoted with && operator as T&&. So the following line of code compiles without any error:

string& s1 = "Hello";

Also the following line works fine:

const string&& s1 = "Hello";

So an Rvalue can bind to

  • A constant Lvalue reference
  • A RValue reference

Now we will take a look at overload resolution with RValues and LValues as parameter.

void f1(string& s){
    cout<<"void f1(string& s):"<<s<<endl;
}

void f1(string&& s){
    cout<<"void f1(string&& s):"<<s<<endl;
}

int main()

{
    string s = "Hello";
    string&& s1 = "Hello";
    f1(s);
    f1(s1);
    return 0;
}

The output of this program is:

void f1(string& s):Hello
void f1(string& s):Hello

However we expected that call to f1(s1) will resolve to the function void f1(string&& s). This is not the case because compiler treats a named Rvalue reference as an Lvalue.

void f1(string& s){
    cout<<"void f1(string& s):"<<s<<endl;
}

void f1(string&& s){
    cout<<"void f1(string&& s):"<<s<<endl;
}
int main()

{
    string s = "Hello";
    f1(s);
    f1("Hello");
    return 0;
}

The output of this program is:

void f1(string& s):Hello
void f1(string&& s):Hello

This is as expected because “Hello” is an unnamed Rvalue reference and the call f1(“Hello”) resolves to void f1(string&& s).

We can also cast a Lvalue reference to Rvalue as shown below:

void f1(string& s){
    cout<<"void f1(string& s):"<<s<<endl;
}

void f1(string&& s){
    cout<<"void f1(string&& s):"<<s<<endl;
}

int main()

{
    string s = "Hello";
    f1(s);
    f1(static_cast<string&&>(s));
    return 0;
}

The output of this program is:

void f1(string& s):Hello
void f1(string&& s):Hello

The Standard Library provides a function std::move to obtain an Rvalue reference from a type which can be used instead of casting:

 
f1(std::move(s));

With this basic idea of RValue references we will move into forwarding & move semantics of C++11 in the next posts.

Comments
  1. […] the last post we discussed about RValue references in C++11.The next logical step will be to move forward to […]

  2. Lin says:

    Hi, thanks for the great tutorial!
    I seem to find a typo, where the const keyword should be switched in the following 2 lines of code:

    string& s1 = “Hello”;

    Also, the following line works fine:

    const string&& s1 = “Hello”;

Leave a reply to Lin Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.