0

I have done some experimentation on rvalue references with the TDM-GCC 4.6.1 compiler and made some interesting observations that I cannot explain away with theories. I would like experts out there to help me explain them.

I have a very simple program that does not deal with objects but int primitives and that has defined 2 functions: foo1 (returning a local variable by rvalue reference) and foo2 (returning a local variable by value)

#include <iostream>

using namespace std;

int &&foo1();
int foo2();

int main()
{

int&& variable1 = foo1();
//cout << "My name is softwarelover." << endl;
cout << "variable1 is: " << variable1 << endl; // Prints 5.
cout << "variable1 is: " << variable1 << endl; // Prints 0.

int&& variable2 = foo2();
cout << "variable2 is: " << variable2 << endl; // Prints 5.
cout << "variable2 is still: " << variable2 << endl; // Still prints 5!

return 0;
}

int &&foo1() {

int a = 5;
return static_cast<int&&>(a);
}

int foo2() {

int a = 5;
return a;
}

It seems the value returned by foo1 and received by variable1 dies out after some time - perhaps, a brief period of some milliseconds. Notice that I have prevented cout from printing "My name is softwarelover" by commenting it out. If I allow that statement to run, the result is different. Instead of printing 5, 0 it prints 0, 0. Seems like it is because of the time-delay introduced by "cout << "My name is softwarelover." that 5 turns into 0.

Is the above how an rvalue reference is supposed to behave when referring to a primitive integer which a function returned by reference as opposed to return-by-value? By the way, why is it 0, why not garbage?

Notice also that variable2 never seems to die out, no matter how many times I print it with cout! variable2 refers to a primitive integer which a function returned by value, not return-by-reference.

Thanks.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
softwarelover
  • 1,009
  • 1
  • 10
  • 22
  • 3
    How do you know 0 is not garbage? – R. Martinho Fernandes Sep 04 '12 at 16:41
  • i wish we would not have this wrong accepted answer: http://stackoverflow.com/questions/9467872/addresses-and-lifetime-of-rvalue-references-or-of-xvalues-in-general – Johannes Schaub - litb Sep 04 '12 at 16:55
  • Never return automatic objects by rvalue reference. Moving is exclusively performed by the move constructor, not by `std::move`, and not by merely binding an rvalue to an rvalue reference. [related FAQ](http://stackoverflow.com/questions/3106110/) – fredoverflow Sep 04 '12 at 17:17
  • 1
    @FredOverflow: Shouldn't that be: Never return automatic objects by **any** kind of reference? – Grizzly Sep 04 '12 at 21:01
  • @Grizzly: Sure, but people (hopefully) already understand the case with lvalue references :) – fredoverflow Sep 05 '12 at 07:20
  • @FredOverflow: Why is it that a const lvalue reference is allowed to receive an integer passed-by-value from a function? Yes, we cannot change the content since the lvalue was declared as a const. But is it still not a reference that is (dangerously) pointing at a temporary location on the stack? – softwarelover Sep 05 '12 at 08:08
  • 1
    Because there is a special rule that extends the lifetime of a temporary if the prvalue whose evaluation creates that temporary is bound to a local lvalue reference to const or a local rvalue reference. – fredoverflow Sep 05 '12 at 08:10

1 Answers1

5

Rvalue references are still just references. A reference to a function local variable is invalid after the function returns. You're lucky your rvalue reference is 5 for any time at all after the function call, because it is technically invalid after the function returns.

Edit: I'm expanding upon my answer, hoping that some people will find some extra detail useful.

A variable defined inside a function is a function local variable. The lifetime of that variable is limited to inside the function that it was declared in. You can think of it as being 'destroyed' when the function returns, but it's not really destroyed. If it's an object, then its destructor will be called, but the memory that held the variable is still there. Any references or pointers you had to that variable still point to the same spot in memory, but that memory has been re-purposed (or may be re-purposed at some indeterminate time in the future).

The old values (in your case '5') will still be there for a while, until something comes along and overwrites it. There is no way to know how long the values will still be there, and no one should ever depend on them still being there for any amount of time after the function returns. Consider any references (or pointers) to function local variables invalid once the function returns. Metaphorically, if you go knocking on the door you probably won't find the new tenant agreeable.

SingerOfTheFall
  • 29,228
  • 8
  • 68
  • 105
user1646801
  • 259
  • 2
  • 7
  • After all the discussions we have had, I think I can now formulate an answer to the question why variable1 died out and why variable2 lived on. Function foo1() returns an rvalue reference. In this expression the returned rvalue reference is unnamed and therefore an xvalue. int&& variable1 = foo1(); We know that an xvalue is a "soon-to-expire" value. Therefore, despite being captured by variable1, xvalue simply vanished (5 to 0) as expected. On the other hand, int&& variable2 = foo2(); is equivalent to saying int&& variable2 = 5; which is perfectly alright. Therefore, it lived on. :-) – softwarelover Sep 06 '12 at 18:22