0

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?

dasfex
  • 1,148
  • 2
  • 12
  • 30
  • 2
    Placement-new'ing an object on top of an existing object is undefined behavior. So is explicitly calling the destructor on an object that was not placement-new'ed. So both examples are wrong. – Remy Lebeau Sep 05 '21 at 10:49
  • @RemyLebeau, can you add an answer? – dasfex Sep 05 '21 at 10:50
  • Does this answer your question? [should the destructor be called with placement new even on the same type](https://stackoverflow.com/questions/55225263/should-the-destructor-be-called-with-placement-new-even-on-the-same-type) – dewaffled Sep 05 '21 at 10:53
  • @dewaffled my qusetion mostly about placement new not the destructor. – dasfex Sep 05 '21 at 10:57
  • @RemyLebeau "So is explicitly calling the destructor on an object that was not placement-new'ed" Where are you getting this? [see](https://eel.is/c++draft/basic.life#5). – n. m. could be an AI Sep 05 '21 at 11:43
  • @RemyLebeau That is incorrect on both count. Calling the destructor is fine but then you **have** to placement new to replace it or the destructor will eventually be called twice and that would be UB. Second, if the destructor has no side effects it can be skipped. I think that part is a recent addition – François Andrieux Sep 05 '21 at 13:16
  • 1
    See __Storage reuse__ here https://en.cppreference.com/w/cpp/language/lifetime Specifically _"...However, if a program ends the lifetime of an non-trivially destructible object that is a variable explicitly, __it must ensure that a new object of the same type is constructed in-place__ (e.g. via placement new) before the destructor may be called implicitly, ..."_ So case (2) is well defined. – Richard Critten Sep 05 '21 at 15:17

2 Answers2

5

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)

spectras
  • 13,105
  • 2
  • 31
  • 53
1

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.

Toni Georgiev
  • 131
  • 1
  • 4