Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it OK not to call the destructor on placement new allocated objects?

Tags:

c++

Say I have a fixed memory buffer

char *buffer; 

And I allocate my structures in that buffer using placement new

struct S
{ 
    std::tuple<int, double, char> m_data; 
    auto getRecord() 
    { 
        return m_data;
    }
};

S *newS = new(buffer + offset)S; 

I know that I'm supposed to manually call the destructor of such allocated items but if there's no bookeeping / resource management involved is it ok to omit this? In other words if the destructor of the classes using the buffer is not doing anything (similar to ~S() above) is it ok to skip this step? If that's the case can I reuse the buffer without destroying the previous tenants?

like image 346
Lorah Attkins Avatar asked Dec 29 '16 18:12

Lorah Attkins


2 Answers

The standard has a rule in section 3.8 [basic.life] that covers this:

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete-expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

Lots of experts are in agreement that "depends on the side effects produced by the destructor" is far too vague to be useful. Many interpret it as a tautology meaning "If the program has undefined behavior when the destructor side effects are not evaluated, then failing to call the destructor causes undefined behavior". See Observable behavior and undefined behavior -- What happens if I don't call a destructor?

If your type has a trivial destructor (which appears to be the case in your example), then calling it (or failing to call it) has no effect whatsoever -- calling a trivial destructor does not even end the life of the object.

The lifetime of an object o of type T ends when:

  • if T is a class type with a non-trivial destructor, the destructor call starts, or
  • the storage which the object occupies is released, or is reused by an object that is not nested within o.

That is, if T doesn't have a non-trivial destructor, the only way to end the lifetime of object o is to release or reuse its storage.

like image 154
Ben Voigt Avatar answered Sep 22 '22 16:09

Ben Voigt


Technically the destructor call is not required. Practically better safe than sorry (do call the destructor)

like image 34
Paul Stelian Avatar answered Sep 24 '22 16:09

Paul Stelian