2

Assuming the code compiles, is there any difference between:

A && a = .....

and

A &  a = .....

? a is a local variable in a function or method, not a parameter.

By giving the rvalue-reference a name (a) it is effectively an lvalue for the rest of the scope? i.e. even with the former form, you'd have to use move(a) to enable pilfering when passing a to another function?

I appreciate there might be other problems with the second form, which prevent compilation, for example you can't have a (non-const) reference to a temporary. So, yes, I'm curious to know all the differences, but first I want to confirm my hunch that they are fully equivalent for the remainder of the scope.

Update: as an example of this 'temporary' problem, which @KerrekSB has reiterated, sometimes you must make the plain reference const. In that case, my question is whether there is a difference between:

const A && a = .....

and

const A &  a = .....
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • No, there is no difference between `A const&& a = ...` and `A const& a = ...`, if that's your only question. – ildjarn Dec 20 '11 at 05:01
  • @ildjarn, that's my main question. And also the non-const version (assuming the code compiles). There is no difference in the lifetime of `a` or in anything else which could cause the program to behave a little differently? – Aaron McDaid Dec 20 '11 at 05:10
  • 1
    If you mean, what's the difference between `A const& a = ...` and `A&& a = ...`, then the only difference is that you're allowed modify non-const data members and call non-const member functions of the latter but not the former -- both are the same in that they're merely extending the lifetime of a temporary. – ildjarn Dec 20 '11 at 05:13
  • @ildjarn, Perfect. In all the talk of `&&` on the interwebs, I hadn't seen anybody explicitly point out that it can be used as a way to extend the lifetime of a temporary. This behaviour seems to be an unexpected benefit. (Or maybe some people would frown upon this! "Temporaries should be temporary, darnit!") – Aaron McDaid Dec 20 '11 at 05:17
  • @Aaron it's a well designed property. Foreach loops work by storing the container given in the for loop as `auto &&c = container`. If the container is a temporary, it is important that lifetime is lengthened. – Johannes Schaub - litb Dec 24 '11 at 20:20
  • By "unexpected benefit" I meant that many people who don't understand, or never will understand, rvaluerefs will find it a useful way to extend lifetime of temporaries. I agree it was well-designed, but some of the less experienced developers will (naively?) say "I don't understand move-semantics, but I am glad not be stuck with const refs to temporaries". (On a related note, I remember making my own foreach macro some time ago and storing a reference to a Range object (which referenced the container) inside an autoptr in order to work around the `const &` limitation.) – Aaron McDaid Dec 25 '11 at 00:04
  • The title of this post is exactly what I'm wondering too, but not in comparison to a normal reference. Is there a point in declaring a local variable like Foo&& someFoo = makeAFoo(); vs. Foo someFoo = makeAFoo(); – Oscar Feb 28 '22 at 08:02

4 Answers4

1

This works:

int foo();

int && a = foo();

This doesn't:

int & b = foo(); // error, cannot bind rvalue to non-const ref
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I'm new to all this C++11 mumbo jumbo; where does the return value of `foo` live? – Seth Carnegie Dec 20 '11 at 04:27
  • 1
    He said he knew about that in his post :D @Seth: Referring to it is C++11, but where it lives is definitely not. – Puppy Dec 20 '11 at 04:28
  • I already mentioned that in my question :-) "for example you can't have a (non-const) reference to a temporary" This is the error message that earlier versions of g++ gave I think. I'll edit my question appropriately. – Aaron McDaid Dec 20 '11 at 04:29
  • @DeadMG what? I was just asking where the value would live; it can't remain where it was on the stack, can it? – Seth Carnegie Dec 20 '11 at 04:30
  • @AaronMcDaid: If you have `int const bar();`, then you could bind `int const && c = bar();` -- but this is essentially entirely useless. – Kerrek SB Dec 20 '11 at 04:32
  • @SethCarnegie, I'm sure I did some experiments on that a few hours ago, but I can't remember exactly what I got. Normally, yes, the return value of `foo()` would be discarded at the end of the statement. An exception (which has been around for some time) is to use a const reference - in which case it hangs around for longer. That is not C++11 magic. – Aaron McDaid Dec 20 '11 at 04:36
  • @AaronMcDaid yeah I know, but why does `int && a = foo();` work? that is not a `const` reference. I guess the same question still applies for `const` reference though; in `const int& a = foo();` where does the return value live? I would think it had to be moved from its position on the stack so it didn't get clobbered. – Seth Carnegie Dec 20 '11 at 04:37
  • 1
    @SethCarnegie, ignoring `&&` for now. `const int& a = foo();` stays on the stack, but it won't get clobbered. When any function is called, the caller (as far as I know) sets aside space on the stack to store the return value. I think this `const&` notation then causes that space to be magically reinterpreted to be like a new local variable, after the return. – Aaron McDaid Dec 20 '11 at 04:48
  • 1
    @SethCarnegie, check [this question](http://stackoverflow.com/questions/1565600/how-come-a-non-const-reference-cannot-bind-to-a-temporary-object) to clarify the pre-C++11 issues we're discussing. Somebody (quoting the standard?) said "temporaries die at the end of the statement, unless they are bound to const reference, in which case they die when the reference goes out of scope" – Aaron McDaid Dec 20 '11 at 04:50
1

The difference between A && a= ... and A & a= ... is that the former can bind to a temporary while the latter cannot. The C++ standard now specifies that a reference has to be non-volatile const or an rvalue reference to bind to a temporary (see 8.5.3 References [dcl.init.ref]), which can then extend the lifetime of the temporary (see 12.2 [class.temporary]).

EDIT: If you think about what rvalue references allow you to do, they have to be able to bind to temporaries, otherwise, you would not be able to express move semantics in C++.

MSN
  • 53,214
  • 7
  • 75
  • 105
  • I liked this answer originally because it added to my knowledge of if and when it is possible to initialize such variable. I knew that `A&` wouldn't bind temporaries, but I didn't know that `A&&` did. (In fact, at first I assumed that `std::move` was a piece of core-language magic.) But I am curious about whether they are any diffent after they have been initialized. I think the answer is no, apart from the `decltype` point made by @Johannes – Aaron McDaid Dec 25 '11 at 00:48
1

There might be differences with operator A& and operator A&& being invoked in the one and other case respectively (You would need to check the spec and the DRs that modified/fixed that part of the spec).

What definitely is different is decltype(a) for both cases.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

(Answering my own question just to summarize what I think I've learned.)

In summary, what's the difference between A &a = ... and A &&a = ...? And between const A &a = ... and const A &&a = ...? If they are names of function parameters, then it affects function lookup clearly, but I'm just talking about local variables. The differences are:

  1. (Obvious) const must be obeyed. A const reference can't be used to modify the object.
  2. A &a = foo(); can't bind to a temporary (nothing new there), but the other three forms can and will extend the lifetime to the of the local variable.
  3. decltype(a) will be different.
  4. (Assuming there was no const problem), the initialization will likely be the same, except if there are operator & or operator && conversions to choose from.

In summary, there are fewer differences than I had originally assumed. Months ago, I had thought that

A &&a =...;
foo(a);

would call foo(A&&). But instead foo(move(a)) is required.

A C++03 programmer can fairly safely use A &&a = to extend the lifetime of temporaries without having to worry about other unexpected differences.

(Thanks to all)

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88