Can a Second Const Reference Extend the Lifetime of a Temporary

557 Views Asked by At
  • Background:

I noticed that the signature of std::max is:

template<typename T>
const T& max(const T&, const T&);

and I wondered about the implications of returning a reference to a const T...

If we pass in two L-values, it makes sense we could return a reference to one of the two. But if we pass in two PR-values, what is being returned and is it a safe thing to use?

Problem:

I spoke with some colleagues and here is a minimal working example of the issue: http://cpp.sh/4en4

#include <iostream>
int glob = 100;
class temp{
  int* val;
public:
  temp(int n = 0){
    val = new int(n);
  }
  void print() const{ std::cout << "I store " << *val << std::endl; }
  ~temp(){
    std::cout << "temp object died" << std::endl;
    delete val;
    val = &glob;
  }
};
const temp& foo(const temp& a){
  return a;    
}

int main(){
  const temp& b = foo(2); 
  std::cout << "Is it safe?" << std::endl;
  b.print(); 
}

Without optimization:

temp object died
Is it safe?
I store 100

With moderate:

temp object died
Is it safe?
I store -1992206527

Running this with different levels of optimization gives different results. In all cases, though, it seems that returning the reference does not prolong the lifetime of the local object; its desctructor is still called, although in one case we seem to recover a reference to the destroyed object and in the other, we seem to have a dangling pointer.

The Standard:

Quoting from the C++ Standard, document number N4618:

12.2 item 6:

... when a reference is bound to a temporary. 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:
(6.1) — A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.
(6.2) — The lifetime of a temporary bound to the returned value in a function return statement (6.6.3) is not extended; the temporary is destroyed at the end of the full-expression in the return statement."

From (6.1), it would seem a temporary foo(2) should exist for the entire statement that initializes b.

From (6.2), it would seem that the local 'a' gets destroyed, which actually destroys the temporary foo(2), resulting in b taking on a destructed value.

My Questions:

1a. What is the full-expression that contains the temporary generated by foo(2) in const temp& b = foo(2);

1b. Can a 2nd const reference extend the lifetime of a temporary?

  1. Why is std::max implemented as such, given the apparent danger?
0

There are 0 best solutions below