views:

58

answers:

4

Hi!

I'm reading something about overload resolution and I found something that bothers me...In the following code:

int const& MaxValue(int const& a, int const& b)
{
    return a > b ? a : b;
}

void SomeFunction()
{
    short aShort1 = 3;
    short aShort2 = 1;
    int const & r2 = MaxValue(aShort1, aShort2); // integral promotion
    //is it safe to pass r2 around before function SomeFunction completes
    // CallSomeOtherFunctionThatCallsSomethingElse(r2);

}

My understanding is that two temporary int's are created and they're allocated on the stack belonging to SomeFunction. So when MaxValue returns, r2 referencing to one of those temp variables (in this case, the one that holds value 3). Thus, is should be safe to pass r2 around.

The question is, if my understanding is fine, is this a standard behavior (please verify)? If not, please explain what is happening in above code.

Many Thanks

+3  A: 

Yes, your understanding is fine and this is standard behaviour.

Except this:

Thus, is should be safe to pass r2 around.

which I do not understand.

// EDIT

You should use pointers instead of references here to achieve the same but without the problem. Using address of an argument passed by const reference is OK only within the function because it may point to local copy of an object.

adf88
I concur with your answer, and the qualification to it.
Brian Hooper
+4  A: 

Welcome to why implicit casts suck. You now have a reference to a temporary, which has been destroyed. Hope you didn't want to do anything with it.

DeadMG
+1  A: 

You should return and pass by value for simple types.

DanDan
+2  A: 

Short answer: it is unsafe.

The standard guarantees that a temporary variable can be bound to a constant reference in which case the lifespan of the temporary expands to the lifetime of the bound reference. The problem in your particular case is what reference is actually binding the temporary.

When you call MaxValue( s1, s2 ), two temporary variables of type int are created and bound to the parameter arguments a and b in MaxValue. This means that the lifespan of those temporaries is extended to the completion of the function. Now, in the return statement of your function you are taking a second reference to one of the temporaries and that second reference will not extend the lifetime. r2 will not further extend the lifetime of the object, and you have a dangling reference.

Note that due to the separate compilation, the compiler cannot possibly know from outside of MaxValue whether the returned reference is to one of the arguments or to a completely different object that is not a temporary:

int const & OtherMaxValue( int const & a, int const & b ) {
   static int value = 0;
   value = (a > b? a : b);
   return value;
}

So it cannot possibly guess whether any or which of the temporaries lifetime needs to be extended.

As a side note, for small objects (such as all integer types) passing by reference may be actually worse than passing by value. Also there is already an std::max template that actually implements this functionality.

David Rodríguez - dribeas