23

I am writing a template class which internally manages an array of the given type. Like this:

template<typename T>
class Example {
    // ...
private:
    T* objects; // allocated in c'tor (array), deleted in d'tor
    // ...
};

I was wondering if C++ calls the destructor of each object in objects when I delete it via delete[] objects;.

I need to know this, because the objects in my class do not contain sensible values all the time, so the destructors should not be called when they don't.

Additionally, I'd like to know if the destructors would be called if I declared a fixed-sized array like T objects[100] as part of Example<T>.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Mixthos
  • 1,067
  • 1
  • 8
  • 13
  • 15
    "because the objects in my class do not contain sensible values all the time" This class sounds broken. – R. Martinho Fernandes Jun 27 '13 at 13:40
  • The class is a collection which allocates memory ahead of time, which it doesn't always use. I don't need to fill that space with NULLs because the class already knows which elements are in use and which are not. – Mixthos Jun 27 '13 at 13:56
  • If `new []` calls constructors it is only logical for `delete []` to call destructors. It is only logical. – dtech Jun 27 '13 at 13:59
  • I didn't know that new[] calls constructors... what does it do when there's no public default constructor? – Mixthos Jun 27 '13 at 14:01
  • 1
    @Mixthos: no usable ctor: the code is ill-formed – Balog Pal Jun 27 '13 at 14:07
  • @Mixthos *What does it do when there's no public default constructor?* It fails to compile. – Peter Wood Jun 27 '13 at 14:12
  • @Mixthos : consider [`std::vector`](http://en.cppreference.com/w/cpp/container/vector) instead - you can pre-allocate memory using [`reserve`](http://en.cppreference.com/w/cpp/container/vector/reserve), and then add objects into the vector when you want – Sander De Dycker Jun 27 '13 at 14:12
  • If your object cannot be destroyed safely then there is a serious problem with the class. Hacking around to try to avoid destructors won't fix that. – Pete Becker Jun 27 '13 at 14:13

6 Answers6

35

If T has a destructor then it will be invoked by delete[]. From section 5.3.5 Delete of the c++11 standard (draft n3337), clause 6:

If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted. In the case of an array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion of their constructor; see 12.6.2).

The destructor for a type T will also be invoked for each element in an array of T[] when the array is not dynamically allocated and array goes out of scope (lifetime ends).


I need to know this, because the objects in my class do not contain sensible values all the time, so the destructors should not be called when they don't.

But, there seems to be a very significant problem with an object that can acquire a state where it cannot be destructed.

hmjd
  • 120,187
  • 20
  • 207
  • 252
5

Yes, the destructor will be called for all objects in the array when using delete[]. But that shouldn't be an issue, since the constructor was called for all objects in the array when you used new[] (you did, right ?) to allocate it.

If a constructed object can be in such a state that calling the destructor would be invalid, then there's something seriously wrong with your object. You need to make your destructor work in all cases.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • If you implement something like e.g. `std::vector` it makes sense to speculatively allocate more memory than needed, by e.g. rounding to the next power of two, to avoid moving the elements around all the time. There is nothing wrong with this per se, although it does invite a lot of bugs into the code base. – asynts Mar 31 '21 at 08:47
3

delete [] does call the destructor for each element of the array. Same happens for a member array (your T objects[100]).

You want to keep it as pointer, and design the destructor (and copy constructor, and copy assignment operator, see rule of three/five) for your template to deal with "non-sensible" values pointed to by objects.

Community
  • 1
  • 1
Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
2

The answer is yes. Destructor for each object is called.

On a related note, you should try to avoid using delete whenever possible. Use smart pointers (e.g.,unique_ptr, shared_ptr) and STL containers (e.g., std::vector, std::array) instead.

segfault
  • 5,759
  • 9
  • 45
  • 66
1

delete[] objects is similar (but not identical) to:

for (i = 0; i < num_of_objects; ++i) {
    delete objects[i];
}

since delete calls the destructor, you can expect delete[] to do the same.

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
  • 3
    Not quite accurate. According to the accepted answer which is referring to the standard the destructors are being called in reverse order. – VCSEL Dec 08 '19 at 05:45
0

Yes, delete[] guarantees destructors are called on every object.

Depending on your use case, using Boost pointer containers, or simply containers of smart pointers, might make it a lot easier to have (exception safe) collection of pointers.

Pieter
  • 17,435
  • 8
  • 50
  • 89