14

Here by "simple", I mean a class with non-virtual empty destructor or POD type.

Typical example:

char buffer[SIZE];
T *p = new(buffer) T;
...
p->~T();  // <---- always ?

What happens if we don't call the explicit destructor on p? I don't think it is undefined behavior or memory leak.
Is there any problem with reusing buffer ?

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • @EdChum Why? He's placing a single object on top of that buffer. – Benj May 11 '12 at 06:53
  • @Benj sorry just realised my mistake – EdChum May 11 '12 at 06:53
  • 1
    With placement new, are you also responsible for calling the destructor of any subtypes? – Benj May 11 '12 at 06:55
  • 2
    @Benj: Good question, go ahead and ask it. – MSalters May 11 '12 at 07:02
  • 2
    @EdChum: The only problem with this code is that an automatic buffer might not be correctly aligned for `T`. Solution: declare it as `alignas(T) unsigned char buffer[sizeof(T)]`. – Mankarse May 11 '12 at 07:04
  • @Benj, Ya I am missing this **very important point**. The destructors of the types contained will not be called. Which means I must have to call the destructor explicitly. – iammilind May 11 '12 at 07:04
  • @iammilind Yes that's why it occured to me, the FAQ is rather scant on the details too. – Benj May 11 '12 at 07:07
  • @MSalters, Benj's comment should be an answer than a new question. – iammilind May 11 '12 at 07:08
  • @MSalters Yes, I'm starting to think all the answers to this are wrong, need to research it a bit before I answer though, so go ahead. – Benj May 11 '12 at 07:12
  • @iammilind are we still talking about PODs or not? http://www.fnal.gov/docs/working-groups/fpcltf/Pkg/ISOcxx/doc/POD.html – celavek May 11 '12 at 07:12
  • 2
    @celavek - Yes, it's just that you need to be very careful with POD classes, an empty destructor != POD class. – Benj May 11 '12 at 07:13
  • @Benj "empty destructor != POD class" ... I don't think I implied the opposite so I don't follow – celavek May 11 '12 at 07:22

4 Answers4

12

Technically speaking, assuming that the destructor doesn't release any resources acquired during construction, it may not be necessary.

However, considering the non-technical aspects - maintenance and evolution of the code - I would stick to the best practice - what was constructed, should be destructed. Scenario to consider - what if in the future some changes will determine relevant code to be put in the destructor? Will you remember that you skept the destruction of that type of object?

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
10

For a POD-type or a class with a trivial destructor: no. The lifetime of the object will end when the storage for the object is released or reused. You don't have to call the destructor explicitly if you don't want to.

That said, there's no reason not to. For a type with a trivial destructor the destructor call will generate no code.

If, by a class with an "empty" destructor you are allowing the possibility the class has members or base classes with non-trivial destructors then you may get undefined behaviour if your program relies on these destructors being called.

Note that a user provided destructor is a non-trivial destructor even if it is non-virtual and is empty. Despite this you are still permitted to end the lifetime of an object with such a destructor by simply releasing or reusing its storage provided that your program doesn't depend on any side effects of the destructor. (See 3.8 [basic.life] / 4 of ISO/IEC 14882:2011)

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • "_you may get undefined behaviour if your program relies on these destructors being called._" this statement does not make sense. You get defined behaviour, the behaviour of your code. – curiousguy Jul 20 '12 at 19:11
  • 1
    @curiousguy: If the code has a defined behaviour then, by definition, it can't be relying on such destructors being called. I'm not sure that this part of the standard says very much other than circularly give a hint at the definition of "rely on" but I don't think that it's inconsistent. – CB Bailey Jul 20 '12 at 20:45
  • "_I don't think that it's inconsistent_" No. It's just tautological. You could as well say that code that expects `cout << "";` to print `Hello, World` is undefined... the std has plenty of absurd statements, and this is one my favourites. – curiousguy Jul 20 '12 at 23:42
  • 1
    @curiousguy: Undefined behavior merely means that the C++ standard makes no claims as to what your program will or will not do, and any bad things that happen are your fault. As such, it should be avoided. Yes, something happens, but the C++ standard can't guess what it would be. – Mooing Duck Jul 21 '12 at 00:04
  • @MooingDuck "_Yes, something happens,_" No, nothing happens. "_but the C++ standard can't guess what it would be._" There is no guessing. If you don't call a function, then it doesn't get called. Period. – curiousguy Jul 21 '12 at 00:25
  • 1
    @curiousguy right, but what hhappens when you dont call that function? Does the compiler detect that and optimize that variable out, causing the entire program to randomly fail in unexpected ways? – Mooing Duck Jul 21 '12 at 16:38
  • @MooingDuck What happens when you don't call `free`? when you don't call `delete`? 1) Memory is not returned to the `malloc` pool. 2) Destructor is not called. Memory is not returned to the `operator new` pool. The compiler will not optimise out the `malloc` call, or the `new` call just because you have a memory leak. – curiousguy Jul 21 '12 at 17:05
1

If your class handles some resources(heap memory, handles, counters, mutexes...) or contains some fields which handle resources, this resources will be not freed if you do not call destructor explicitly. Otherwise there no any troubles with destruction. You can consider non-destructed class as a garbage in memory and construct new one freely in the same place.

inkooboo
  • 2,904
  • 1
  • 19
  • 24
  • He's talking about POD types ... why would he hold a mutex, counter etc. then. – celavek May 11 '12 at 06:58
  • POD may contain pointer or handle to mutex which can be acquired during construction/lifelime of object – inkooboo May 11 '12 at 07:02
  • 3
    @inkooboo: a POD may contain a pointer but can only contain a handle if the handle type is also POD. The mutex can't be acquired during construction of a POD object as that would imply that the POD had a non-trivial constructor. – CB Bailey May 11 '12 at 07:07
0

Yes, you have to call destructor explicitly (please keep in mind side-effects of T, i.e. freeing some additional memory). Also, you have to be careful about memory alignment when using placement new.

If you wish, you could reuse buffer memory.

Please also refer to http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14

Greg
  • 1,660
  • 13
  • 12