11

I have this code (simplified version):

const int& function( const int& param )
{
     return param;
}

const int& reference = function( 10 );
//use reference

I can't quite decide to which extent C++03 Standard $12.2/5 wording

The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference...

is applicable here.

Is reference variable in the code above valid or dangling? Will the reference in the calling code prolong the lifetime of the temporary passed as the parameter?

sharptooth
  • 167,383
  • 100
  • 513
  • 979

4 Answers4

12

A full-expression is an expression that is not a subexpression of another expression. In this case, the full-expression containing the call function( 10 ) is the assignment expression:

const int& reference = function( 10 );

In order to call function with the argument 10, a temporary const-reference object is created to the temporary integer object 10. The lifetime of the temporary integer and the temporary const-reference extend through the assignment, so although the assignment expression is valid, attempting to use the integer referenced by reference is Undefined Behavior as reference no longer references a live object.

The C++11 Standard, I think, clarifies the situation:

The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:

...

— A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.

"The temporary to which the reference is bound ... persists for the lifetime of the reference". In this case, the lifetime of the reference ends at the end of the assignment expression, as does the lifetime of the temporary integer.

Community
  • 1
  • 1
Daniel Trebbien
  • 38,421
  • 18
  • 121
  • 193
3

This will compile, but you will end up with a dangling reference. param is freed after function returns.

  1. function is called with a reference to the temporary, anonymous object
  2. function returns the reference
  3. now that function has returned the temporary param is released
  4. the reference is now dangling as the object was destroyed

If you had made it non-const, then it wouldn't have compiled because you cannot pass a non-const reference to an anonymous object.

  • Isn't `param` destroyed at the end of the assignment? "Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created." – Daniel Trebbien Apr 17 '12 at 15:19
2

From the C++11 viepoint a reference returned by a function is not a temporary:

12.12.1 Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5).

A function returning a reference dosn't return prvalue ("pure rvalue"), so it's not a temporary. This seems quite natural: compiler can't manage lifetime of referenced objects, it is programmer's responsibility

Thus, the compiler doesn't provide any liftime guarantes for const int& reference since it is not bounded to temporary.

user396672
  • 3,106
  • 1
  • 21
  • 31
  • … and this is one place where C++11 fixed ambiguous wording of C++03, a fix that should be taken to apply retroactively. – Potatoswatter Apr 17 '12 at 14:58
1

It is this part that is important

The temporary to which the reference is bound

In this case the parameter is bound to the temporary, and will be destroyed after the call.

You cannot extend the lifetime further by passing the reference on.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • 1
    You can't deny that his `reference` is bound to the temporary. There are in fact several references bound to the temporary. The standard is very badly worded here. The intent is, of course, that lifetime is only extended to match the reference initialized with the actual temporary. Regretfully, that's not really what the standard says. – James Kanze Apr 17 '12 at 12:31
  • 2
    @JamesKanze: I agree that the wording is not very precise, but that being said, with a separate compilation model, it would be impossible for the compiler to know that the lifetime of the temporary should be extended at the call site after the function completes. The compiler cannot possibly know whether the returned reference is bound to the same object as the parameter or any other object (i.e. `const int& function( const int& ) { static int i = 0; return i; }`) – David Rodríguez - dribeas Apr 17 '12 at 13:23
  • This answer doesn't address anything… and the temporary is destroyed at the semicolon at the end of the statement, not immediately after the call. – Potatoswatter Apr 17 '12 at 14:56
  • @Potatoswatter - I didn't say *immediately* after the call, but that the lifetime of the temporary depends on the lifetime of the parameter. – Bo Persson Apr 17 '12 at 15:07
  • @BoPersson The parameter lifetime does end at the end of the function. If you mean the lifetime of the temporary depends on the lifetime of the *argument*, that's true, but the temporary and the argument are identical, so it's vacuous. It might be clearer to say that the function call has no effect on the lifetime of its arguments. Edit: I'm not the downvoter. – Potatoswatter Apr 17 '12 at 15:09
  • @Potatoswatter - No, I mean that the reference `param` is bound to the temporary (with the value 10). The lifetime of `param` affects the lifetime of the temporary. The lifetime of `reference` does not. – Bo Persson Apr 17 '12 at 15:17
  • @BoPersson `param` would affect the lifetime of the temporary, but for the fact that the temporary is already guaranteed to outlive `param` anyway. So there is no effect. Yes, `reference` also has no effect, because as @user396672 mentions, the value category of the expression bound to the reference is really what matters. – Potatoswatter Apr 17 '12 at 15:20
  • @DavidRodríguez-dribeas You know what's meant, and I know what's meant, because we know something about how a compiler works, and what it would need to generate in order to make it work. But I still think that the standard actually says something other than what is meant (and what everyone implements, because what it actually says isn't implementable). – James Kanze Apr 17 '12 at 16:35