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?
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With