Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why lifetime of temporary doesn't extend till lifetime of enclosing object?

Tags:

c++

temporary

I know that a temporary cannot be bound to a non-const reference, but it can be bound to const reference. That is,

 A & x = A(); //error  const A & y = A(); //ok 

I also know that in the second case (above), the lifetime of the temporary created out of A() extends till the lifetime of const reference (i.e y).

But my question is:

Can the const reference which is bound to a temporary, be further bound to yet another const reference, extending the lifetime of the temporary till the lifetime of second object?

I tried this and it didn't work. I don't exactly understand this. I wrote this code:

struct A {    A()  { std::cout << " A()" << std::endl; }    ~A() { std::cout << "~A()" << std::endl; } };  struct B {    const A & a;    B(const A & a) : a(a) { std::cout << " B()" << std::endl; }    ~B() { std::cout << "~B()" << std::endl; } };  int main()  {         {             A a;             B b(a);         }         std::cout << "-----" << std::endl;         {             B b((A())); //extra braces are needed!         } } 

Output (ideone):

 A()  B() ~B() ~A() -----  A()  B() ~A() ~B() 

Difference in output? Why the temporary object A() is destructed before the object b in the second case? Does the Standard (C++03) talks about this behavior?

like image 303
Nawaz Avatar asked Aug 04 '11 05:08

Nawaz


People also ask

How can you extend the lifetime of an object?

The lifetime of a temporary object may be extended by binding to a const lvalue reference or to an rvalue reference (since C++11), see reference initialization for details.

What is lifetime of an object?

In object-oriented programming (OOP), the object lifetime (or life cycle) of an object is the time between an object's creation and its destruction.


1 Answers

The standard considers two circumstances under which the lifetime of a temporary is extended:

§12.2/4 There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when an expression appears as an initializer for a declarator defining an object. In that context, the temporary that holds the result of the expression shall persist until the object’s initialization is complete. [...]

§12.2/5 The second context is when a reference is bound to a temporary. [...]

None of those two allow you to extend the lifetime of the temporary by a later binding of the reference to another const reference. But ignore the standarese and think of what is going on:

Temporaries are created in the stack. Well, technically, the calling convention might mean that a returned value (temporary) that fits in the registers might not even be created in the stack, but bear with me. When you bind a constant reference to a temporary the compiler semantically creates a hidden named variable (that is why the copy constructor needs to be accessible, even if it is not called) and binds the reference to that variable. Whether the copy is actually made or elided is a detail: what we have is an unnamed local variable and a reference to it.

If the standard allowed your use case, then it would mean that the lifetime of the temporary would have to be extended all the way until the last reference to that variable. Now consider this simple extension of your example:

B* f() {    B * bp = new B(A());    return b; } void test() {    B* p = f();    delete p; } 

Now the problem is that the temporary (lets call it _T) is bound in f(), it behaves like a local variable there. The reference is bound inside *bp. Now that object's lifetime extends beyond the function that created the temporary, but because _T was not dynamically allocated that is impossible.

You can try and reason the effort that would be required to extend the lifetime of the temporary in this example, and the answer is that it cannot be done without some form of GC.

like image 102
David Rodríguez - dribeas Avatar answered Nov 05 '22 03:11

David Rodríguez - dribeas