dasfex
dasfex

Reputation: 1270

Is using placement new with variable on the stack is correct?

Let's take a look to this code:

A a(123);
new(&a) A(124);

Test says that in this case when program is shutting down destructor ~A() will called once. So if in A we has some pointers as fields we will get memory leak.

A a(123);
a.~A();
new(&a) A(124); 

Here all will be correct. But according to standard using object after destructor calling is undefined behaviour(though mostly compilers provide behaviour without some troubles).

Can I take an address of object which destructor has been called? Is calling placement new on stack variable is correct operation?

Upvotes: 0

Views: 247

Answers (2)

Toni Georgiev
Toni Georgiev

Reputation: 151

Yes, this usage is valid. The storage for an object is independent from the object's lifetime.
By calling the destructor, you are ending the object's lifetime, but that does not mean that the storage is released.

According to the standard, that storage may be reused or released. And what you do is reusing it.
This exact case is well-defined in the standard in basic.life#8

Keep in mind that, because 'a' is a variable with automatic storage, at the end of the scope the destructor for that variable's type will be invoked.

Upvotes: 1

spectras
spectras

Reputation: 13552

Can I take an address of object which destructor has been called?

[edited:] Such an address is valid so if you have a pointer to it, it is valid.
Can you take its address after the fact, I am not fully sure.

basic.life.6 […] After the lifetime of an object has ended and before the storage which the object occupied is reused or released, any pointer that represents the address of the storage location where the object was located may be used but only in limited ways. […] Such a pointer refers to allocated storage, and using the pointer as if the pointer were of type void* is well-defined.

Check out the full text for the all the restrictions, but use in placement-new is allowed.


As for the comments, I would argue both your samples are correct within the scope you showed.

A a(123);
new(&a) A(124);

I would argue this, given what we know in the sample, is correct.

Ending the lifetime of an object by re-using its storage is valid as per basic.life.5. Only condition is the program does not depend on side effects produced by the destructor - to be on the safe side I would only do that on trivially destructible types. Otherwise you need an explicit destructor call, like you did there:

A a(123);
a.~A();
new(&a) A(124); 

I do not see any rule preventing that. The standard even explicitly mentions when such a construct is invalid:

If a program:

  • ends the lifetime of an object of type T with static, thread, or automatic storage duration
  • and another object of the original type does not occupy that same storage location when the implicit destructor call takes place,

the behavior of the program is undefined.

(formatting as bullet points mine)

Though not a definite proof, this passage suggests that in other cases, the behavior is defined. I cannot think of another rule that his would violate.

(Do note I use C++20 version of the standard)

Upvotes: 5

Related Questions