prolonging the lifetime of temporaries

I’ll answer your question… the other way around.

Why did they allowed Foo const& foo = fooByValue(); to begin with ?

It makes life (somewhat) easier, but introduces potential undefined behavior all over the place.

Foo const& fooByReference()
{
  return fooByValue(); // error: returning a reference to a temporary
}

This is obviously wrong, and indeed the compiler will dutifully report it. As per Tomalak’s comment: it is not mandated by the standard, but good compilers should report it. Clang, gcc and MSVC do. I think that Comeau and icc would too.

Foo const& fooByIndirectReference()
{
  Foo const& foo = fooByValue(); // OK, you're allowed to bind a temporary
  return foo;                    // Generally accepted
}

This is wrong, but is more subtle. The problem is that the lifetime of the temporary is bound to the lifetime of foo, which goes out of scope at the end of the function. A copy of foo is passed to the caller, and this copy points into the ether.

I raised the bug on Clang, and Argyris was able to diagnose this case (kudos really :p).

Foo const& fooForwarder(Foo const&); // out of line implementation which forwards
                                     // the argument

Foo const& fooByVeryIndirectReference()
{
  return fooForwarder(fooByValue());
}

The temporary created by fooByValue is bound to the lifetime of the argument of fooForwarder, which dutifully provide a copy (of the reference), copy that is returned to the caller, even though it now points into the ether.

The issue here is that fooForwarder‘s implementation is perfectly fine wrt the standard, and yet it creates undefined behavior in its caller.

The daunting fact though, is that diagnosing this requires knowing about the implementation of fooForwarder, which is out of reach for the compiler.

The only solution I can fathom (apart from WPA) is a runtime solution: whenever a temporary is bounded to a reference, then you need to make sure that the returned reference does not share the same address… and then what ? assert ? raise an exception ? And since it’s only a runtime solution, it is clearly not satisfactory.

The idea of binding a temporary to a reference is brittle.

Leave a Comment