views:

144

answers:

5

Can anybody explain why this code does not generate a compiler error?

class Foo
{
   public:
      int _x;
};

Foo getFoo()
{
   Foo myfoo;
   myfoo._x = 10;
   return myfoo;
}


int _tmain()
{
   // shouldn't this line of code be a compiler error?
   Foo& badfoo = getFoo();

   return 0;
}
A: 

No. getFoo() returns a value, this means that a temporary copy of it will be allocated, and the reference will refer to that copy.

Vlad
The reference is non-const, a temporary cannot be bound to it.
GMan
A: 

You can bind references to temporaries, and they have the lifetime of the reference itself.

If on the other hand getFoo returned Foo&, you'd have some problems because the lifetime of the object would end when the getFoo function ended. Since you're not returning a reference to internal data but rather returning a copy of that data, you're fine.

dash-tom-bang
Binding references to temporaries is only legal for constant references. The compiler should complain about this.
Tyler McHenry
Yes I am aware of this. My code example might not have been the best choice. I'm just trying to understand how I can have a reference to a temporary value object.
kern
A: 

The getFoo method could also be like this:

 Foo getFoo() 

{
   Foo* myfoo = new Foo();
   myfoo->_x = 10;
   return *myfoo;
}

And this is OK... The compiler can't know everything :)

duduamar
No, this leaks memory.
GMan
@GMan - Save the Unicorns: Leaking memory is legal. It wouldn't hurt, most of the time, for a compiler to have memory leak warnings, but they certainly aren't required.
David Thornley
@David: What? Leaking memory is legal, we agree. I'm just pointing out this leaks. Leaks are bad.
GMan
Of course it is not good code (on the contrary - it's pretty bad we agree :)), just wanted to indicate why the compiler can't possibly alert this kind of issue.
duduamar
The other problem with this is that it doesn't do anything that the original code didn't, as far as the reference-to-a-temporary issue. You create a `Foo` on the stack, and then return it by value. The return by value simply creates a temporary copy, just like the original code did. The memory used by the heap-allocated `Foo` is leaked, and nothing is gained.
Tyler McHenry
+4  A: 

This should be a compile error, although it would not be if it were instead

const Foo& badfoo = getFoo();

Since there is a special rule that extends the lifetime of temporary values bound to constant references, but only to constant references, not any reference.

The code you posted gives me the expected compile error of

error: invalid initialization of non-const reference of type ‘Foo&’ from a temporary of type ‘Foo’

on G++ 4.3.2. Which compiler are you using?

Tyler McHenry
My compiler is Visual Studio 2008 ( VC++ )
kern
Then refer to UncleBens' answer; it is legal as an extension provided by VC++, but is illegal in standard C++.
Tyler McHenry
+4  A: 

You are probably using VC++ which allows this as an extension.

main.cpp:18: warning C4239: nonstandard extension used : 
'initializing' : conversion from 'Foo' to 'Foo &'
UncleBens
So based on the comments I've read above I am under the impression that:a) My example wasn't the best.b) The compiler should be generating an error for storing a temp value in a reference variable.Is that the general consensus? My compiler is VC++ ( MS visual studio 2008 ).
kern
What you are doing is non-standard. Turn up the warnings level, and the compiler should warn about it. Compilers support things that are not in the standard. VC++ supports binding rvalues to non-const references. GCC supports variable-length arrays etc.
UncleBens
Thanks. I could have sworn that I had upped the compiler warnings setting but apparently I had not.Thanks. That gives me what I was looking for.
kern