Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
334 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...