Architecture logicielle & Développement

Traps of the delete operator | 0 vote(s)

Tags:

La version française de ce billet est disponible ici.

At a first glance, everything looks easy. The delete operator is used to deallocate memory that has been allocated previously using operator new. It also executes the destructor of the deallocated object in order to free its owned resources.

of course, it becomes more complicated when one sees that another operator delete exists, whose name is delete array in the C++ standard (its notation is delete [], while the notation of the "normal" on is delete object). The purpose of delete is to free memory blocs that has been allocated with new array'' (new []).

The very first conclusion is the following: if a memory bloc has been allocated using new object it must be freed using delete object. If it has been allocated with new array then it must be deallocated with delete array. An operator error will have no effect on compilation but is likely to have a disastrous effect at runtime, the standard explicitly saying that the program behavior is unspecified in this case (5.3.5 §2)[1]. This is the first trap of the delete operator.

The second trap is more difficult to foresee: if you destroy an object whose type is incomplete and if this object destructor is non trivial, the behavior of the program is again undefined (5.3.5 §5). In most cases, the program will still function but the compiler will have generated a trivial destructor for this incomplete type and of course this will prevent the release of the resources that are owned by the destroyed object [2].

A third trap deals with the way the delete operator works: the standard doesn't require that the pointer parameter is left unchanged (5.3.5 §4). This is an implementation choice. It means that it's forbidden to compare the value of a deallocated pointer - such a value is considered to be invalid anyway (5.3.5 §4). As a consequence, this code exhibits undefined behavior:

// vector v contains pointers that can be
// stored multiple times, I want to avoid
// to release twice the same element
std::sort(v.begin(), v.end());
T *p = NULL;
for (size_t i=0; i<v.size(); i++) {
  if (v.at(i) != p) {
     delete v.at(i);
     p = v.at(i);
  }
}

In his FAQ, Bjarne Stroustrup explains that this paragraph allows the compiler vendors to set the deleted pointer to 0 - but in the end, it's not a very good idea, not to mention that it's not always possible[3].

To end this (non exhaustive list) list, a fourth problem must be described. When delete array is called to deallocate an array, it will call the object destructors "in the reverse order of the completion of their destructor" (5.3.5 §6). It will destroy the last element, then the previous one, and will end by destroying the first array element. It is therefore forbidden to make a reference to any other array element in the element destructor. A contrario, the element destruction order in a std::vector<> is left unspecified (this destruction is done with an explicit call to the destructor to avoid deallocation of the already allocated memory).

To bring some light in this world of traps, I must share a good thing with you - something that is often ignored: as per (5.3.5 §2) the destruction of a null pointer has no effect. There's no need to write if (pointer != NULL) delete pointer;, your implementation does this for you!

As we can see, and despite its apparent simplicity, the use of the delete operator has to be stringent if we want to avoid its numerous traps - and to avoid the auto destruction of the program as well.

Notes

[1] In this document, the notation (x.y.z § n) refers to section x.y.z paragraph n of the ISO/IEC C++ Standard

[2] we'll discuss that in detail in a coming ticket about std::auto_ptr<>

[3] we'll also note that functions like delete_safe(T*&) whose goal is to nullify the parameter after they deallocated it suffer the exact same issue: what happen if the parameter is a function return value?

Trackbacks

Aucun trackback.

Les trackbacks pour ce billet sont fermés.

Commentaires

1. Le mardi 12 février 2008 à 04:01, par Anonymous

Gravatar

je tenais juste à te dire qu'il est très plaisant de surfer sur ton blog ;)

2. Le mercredi 13 février 2008 à 09:45, par Emmanuel Deloget

Gravatar

Merci.

J'aurais toutefois préféré un commentaire dont le but n'était pas se spamer mon blog.

Ajouter un commentaire

Si votre navigateur est compatible, vous pouvez vous aider de la barre d'outils placée au-dessus de la zone de saisie pour enrichir vos commentaires.