Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const reference to a temporary object becomes broken after function scope (life time)

While asking this question, I learned const reference to a temporary object is valid in C++:

int main ()
{
  int a = 21;
  int b = 21;

  //error: invalid initialization of non-const reference
  //int     & sum = a + b;e [...]

  //OK
  int const & sum = a + b;

  return sum;
}

But in the following example, the const reference refnop refers to a destroyed temporary object. I wonder why?

#include <string>
#include <map>

struct A
{
   // data 
   std::map <std::string, std::string>  m;
   // functions
   const A& nothing()           const { return *this;    }
   void init()                        { m["aa"] = "bb";  }
   bool operator!= (A const& a) const { return a.m != m; }
};

int main()
{
  A a;
  a.init();

  A const& ref    = A(a);
  A const& refnop = A(a).nothing();

  int ret = 0;
  if (a != ref)     ret += 2;
  if (a != refnop)  ret += 4;

  return ret;
}

Tested using GCC 4.1.2 and MSVC 2010, it returns 4;

$> g++ -g refnop.cpp
$> ./a.out ; echo $?
4

The difference between ref and refnop is the call to nothing() which does really nothing. It seems after this call, the temporary object is destroyed!

My question:
Why in the case of refnop, the life time of the temporary object is not the same as its const reference?

like image 336
oHo Avatar asked Jun 21 '13 11:06

oHo


1 Answers

The lifetime-extension of a temporary object can be performed only once, when the temporary object gets bound to the first reference. After that, the knowledge that the reference refers to a temporary object is gone, so further lifetime extensions are not possible.

The case that is puzzling you

A const& refnop = A(a).nothing();

is similar to this case:

A const& foo(A const& bar)
{
    return bar;
}
//...
A const& broken = foo(A());

In both cases, the temporary gets bound to the function argument (the implicit this for nothing(), bar for foo()) and gets its lifetime 'extended' to the lifetime of the function argument. I put 'extended' in quotes, because the natural lifetime of the temporary is already longer, so no actual extension takes place.

Because the lifetime extension property is non-transitive, returning a reference (that happens to refer to a temporary object) will not further extend the lifetime of the temporary object, with as result that both refnop and broken end up referring to objects that no longer exist.

like image 177
Bart van Ingen Schenau Avatar answered Sep 21 '22 06:09

Bart van Ingen Schenau