When are temporary objects destroyed?
Asked Answered
N

5

29

The following code prints one,two, three. Is that desired and true for all C++ compilers?

#include <iostream>

struct Foo
{
    const char* m_name;

    ~Foo() { std::cout << m_name << '\n'; }
};

int main()
{
    Foo foo{"three"};
    Foo{"one"};   // unnamed object
    std::cout << "two" << '\n';
}
Naominaor answered 19/2, 2010 at 18:51 Comment(1)
Duplicate: #1389185Essam
D
47

A temporary variable lives until the end of the full expression it was created in. Yours ends at the semicolon.

This is in [class.temporary] p4:

Temporary objects are destroyed as the last step in evaluating the full-expression that (lexically) contains the point where they were created.

Your behavior is guaranteed, however, the are exceptions to this rule listed in [class.temporary] p5, p6, and p7:

  1. shortening the lifetime of default-constructed temporary objects in initializers of arrays
  2. shortening the lifetime of default arguments to constructors while an array is copied
  3. extending the lifetime of temporary objects by binding a reference to them
  4. extending the lifetime of temporary objects in a for-range-initializer
Diaphanous answered 19/2, 2010 at 18:54 Comment(4)
... uless the conditions from 12.2/4 are met, which can extend the lifetime of a temporary even further.Semimonthly
@AndreyT: Er, yes. I suppose that may be important to mention.Diaphanous
It might not be important to mention in the context of the original question. But after reading your explicit assertion that says "lifetime of a temporary variable is up when the expression ends" I thought that it is something worth mentioning.Semimonthly
@Andrey: I agree, my original post made it seem unconditional.Diaphanous
S
16

The rules that govern the lifetimes of temporary objects have nothing to do with notion of scope. Scope is a property of a name, and temporary objects do not have names. In other words, temporary objects have no scope.

Most of the time the lifetime of a temporary object ends at the end of the full expression that created that object, which is what you observed in your experiment. This is the general rule that has some exceptions. The main one is that if you immediately attach a reference to your temporary object, the lifetime of the object will be extended to match the lifetime of the reference

const Foo &rfoo = Foo("one");

The above temporary will live as long as rfoo lives.

Semimonthly answered 19/2, 2010 at 19:4 Comment(3)
+1 Scope is a property of a name, and temporary objects do not have names. Does the life time of temporary extend binding to a reference with out const qualifier? Foo &rfoo = Foo("one") ;Bello
I read that the life time of temporary can only be extended binding to a const reference. But the example ideone.com/nTVPZ works fine on VS 2010 but not on gcc ( also the this in both the cases is same in the given link signifying the extending the life temporary even with out const qualifier on VS ). Is gcc or VS correct here ?Bello
@Mahesh: The code is not compilable in standard C++, which is why GCC rejects it. VS accepts it as an extension only because you have extensions enabled. If you disable language extensions in VS, the code will not compile in VS as well.Semimonthly
S
6

The scope of a temporary object like that is just one line. Think about it, you can no longer reference it after the line ends, so why would the object remain around?

If this weren't the case, compilers wouldn't be able to optimize out temporary objects in function calls.

Scratch answered 19/2, 2010 at 18:53 Comment(0)
N
4

Yes, it is desired.

Foo foo("three") creates a normal object which will be destroyed when the scope ends.

Foo("one") creates a temporary object, which is destroyed at the end of the instruction[1]. Why? Because there is no way you can access it after the instruction has ended.

[1] Deliberate simplification: I should have said sequence point.

Navarrette answered 19/2, 2010 at 18:55 Comment(1)
Sequence point has nothing to do with this. The lifetime of the temporary ends at the end of the full expression, even if there is a sequence point at the end of the "instruction" that created the object. For example, in Foo("a"), Foo("b"), Foo("c"); all three temporaries are guaranteed to live to the end of the statement, even though there are sequence points in the middle.Semimonthly
B
2

Because the standards committee goofed. It does it because they chose to make it do it. It's defined to do it this way. It should be considered an anonymous instance with scope the same as if it had been named. From the point of instantiation to the end of the block. Apparently they thought the only use was for passing temporaries into functions where it's pushed on the stack and popped off the stack at the end of a function call...

An unnamed object should still be pushed onto the stack and remain on the stack until the block ends, thus popping it off the stack when expected. Constructing and destructing an object during a single statement is pointless. I'd like to see a single instance/case where this is actually useful. If it doesn't stay in scope for the duration of the block it should most certainly be an error and should at minimum generate a warning.

Banded answered 22/2, 2016 at 14:11 Comment(2)
Talking explicitly of stack is unnecessary; it's perfectly possible to have a usable C++ implementation that doesn't use stack at all and instead allocates everything in static locations. It's also possible for small temporary values to be passed around in registers, not in addressable memory.Mooring
"Constructing and destructing an object during a single statement is pointless." Not if you do it for the side effects, or in a conversion chain. It's so useful a major C++ project like Firefox might have thousands of these constructs all over the place. They are immensely useful. It'd be rather bad if these objects were kept around till the end of the block, the cache pressure would kill the performance of many projects, even if the overall memory usage wouldn't significantly change.Mooring

© 2022 - 2024 — McMap. All rights reserved.