Search code examples
c++new-operatorplacement-newstack-pointer

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?


Solution

  • 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)