20

One of the cool new features of the upcoming C++ standard, C++0x, are "rvalue references." An rvalue reference is similar to an lvalue (normal) reference, except that it can be bound to a temporary value (normally, a temporary can only be bound to a const reference):

void FunctionWithLValueRef(int& a) {…}
void FunctionWithRValueRef(int&& a) {…}

int main() {
     FunctionWithLValueRef(5); // error, 5 is a temporary
     FunctionWithRValueRef(5); // okay
}

So, why did they invent a whole new type, instead of just removing the restrictions on normal references to allow them to be bound to temporaries?

Enlico
  • 23,259
  • 6
  • 48
  • 102
Zifre
  • 26,504
  • 11
  • 85
  • 105
  • 3
    I wonder why this got 3 up votes but 7 favorites. I don't think I've ever favorited a question without voting it up (unless I was out of votes or it was locked). – Zifre May 11 '09 at 20:31
  • 3
    I wonder why somebody thinks in some way and then he expects all others will do exactly as what he does. – user534498 Apr 05 '11 at 05:36
  • 1
    I wonder why "being nice and giving an upvote" is an unreasonable expectation. – Dan Nissenbaum Nov 10 '12 at 20:45

2 Answers2

44

It would be pointless. You would change the thing in the function, and the change would be lost immediately because the thing was actually a temporary.

The reason for the new type stems from the need to be able to decide what actually is an rvalue and what not. Only then you can actually use them for the cool things they are used.

string toupper(string && s) { // for nonconst rvalues
    for(char &c : s) make_uppercase(c);
    return move(s); // move s into a returned string object
}

string toupper(string const& s) { // for the rest
    // calls the rvalue reference version, by passing 
    // an rvalue copy.
    return toupper(string(s));
}

Now, if you have some rvalue and pass it to toupper, the rvalue can directly be modified, because we know the temporary is a throw-away thing anyway, so we can aswell just change it and don't need to copy it. Also, the same observation is used for the thing called move-constructors and move-assignment. The right hand side is not copied, but its things are just stolen away and moved to *this.

If you were to say that rvalues can bind to non-const lvalue references, then you would have no way to figure out whether that references an lvalue (named object) or an rvalue (temporary) in the end.


It's probably more little know, but useful anyway, you can put lvalue or rvalue ref-qualifiers on a member function. Here is an example, which naturally extends the existing semantics of rvalue references to the implicit object parameter:

struct string {
    string& operator=(string const& other) & { /* ... */ }
};

Now, you can't anymore say

string() = "hello";

Which is confusing and is not really making sense most of the time. What the & above does is saying that the assignment operator can only be invoked on lvalues. The same can be done for rvalues, by putting &&.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 1
    +1 Wow thanks for the last part about the lvalues/rvalues only member call! I read a lot about C++0x but didn't see anything about that (I guess it's in the last draft but I didn't read all of it). Can you point me to some documentation about this feature? – Klaim May 10 '09 at 00:42
  • Here is a nice overview: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1821.htm . In the working paper, see 8.3.5, 9.3.1 and 13.3.1. – Johannes Schaub - litb May 10 '09 at 01:05
  • Thanks for this answer, this makes it much clearer. I just wasn't really understanding rvalue references very well. This makes a lot more sense than what I was thinking. – Zifre May 10 '09 at 02:03
  • 2
    I'd like to add that http://thbecker.net/articles/rvalue_references/section_01.html is a great "rvalue references for dummies" article. – rlbond May 10 '09 at 04:51
  • @rlbond: that is a really great article. – Zifre May 10 '09 at 13:08
  • 1
    rlbond, thanks for the nice article. another great one: http://blogs.msdn.com/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx – Johannes Schaub - litb May 10 '09 at 14:33
  • According to current rules, your toupper function won't compile anymore because rvalue references (the return value) cannot be initialized anymore with an lvalue expression (s). Also, returning rvalue references is almost always a bad idea because it may lead to dangling references. Example: string const& foo = toupper("soandso"); – sellibitze Oct 21 '09 at 13:08
  • @sellibitze, oh you are right. I thought along the way "it's local, so it's treated as an rvalue in the return statement". But i missed that it's a reference variable - so it isn't treated as an rvalue. Thanks, i will fix it! Your second complaint is also justified. I will fix it all the way. – Johannes Schaub - litb Oct 21 '09 at 14:35
  • The `&` suffix is interesting - I hadn't spotted that. It's cool that it allows you to properly enforce the ancient meaning of lvalue (something that can appear on the LHS of an assignment). – Daniel Earwicker Oct 21 '09 at 22:32
  • @litb: I think in the 2nd func. _string toupper(string const& s)_, comment should be "for the rest calls the *lvalue* reference version, by passing an *lvalue* copy." instead of rvalue. – legends2k Oct 01 '10 at 21:09
  • @legends what was meant is "by passing a copy of the lvalue. That copy is an rvalue", contracted to "by passing an rvalue copy". – Johannes Schaub - litb Oct 01 '10 at 21:33
  • @litb: Aaah! Now I see it that way! Old habits die hard :) – legends2k Oct 01 '10 at 21:37
  • @litb: Also thanks for explaining about the little known ref-qualifiers! – legends2k Oct 04 '10 at 14:43
12

Because adding a new kind of reference allows you to write two overloads of a method:

void CopyFrom(MyClass &&c)
{
    dataMember.swap(c);
}

void CopyFrom(const MyClass &c)
{
    dataMember.copyTheHardWay(c);
}

The version that accepts the new kind of reference is allowed to modify the variable it receives, because that variable isn't going to be used anywhere else. So it can "steal" the contents of it.

This is the whole reason this feature was added; retaining one type of reference wouldn't achieve the desired goal.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284