96 votes

L'appel du destructeur manuellement est-il toujours le signe d'une mauvaise conception?

Je pensais: ils disent que si vous appelez destructeur manuellement, vous faites quelque chose de mal. Mais est-ce toujours le cas? Y a-t-il des contre-arguments? Situations où il est nécessaire de l'appeler manuellement, où il est difficile / impossible / peu pratique de l'éviter?

122voto

Emilio Garavaglia Points 9189

Toutes les réponses décrivent des cas spécifiques, mais il n'y est une réponse d'ordre général:

Vous appelez la dtor explicitement chaque fois que vous devez tout simplement détruire l' objet (en C++ sens) sans relâcher la mémoire de l'objet réside dans.

Ce qui se passe généralement dans toutes les situation où allocation / libération de mémoire est géré indépendamment de l'objet de la construction / destruction. Dans ces cas, la construction se passe via le placement de nouvelles sur un existant partie de la mémoire et de la destruction qui se passe via explicite dtor appel.

Voici le raw exemple:

{
  char buffer[sizeof(MyClass)];

  MyClass* p = new(buffer)MyClass;
  p->dosomething();
  p->~MyClass();

  MyClass* p = new(buffer)MyClass;
  p->dosomething();
  p->~MyClass();
}

Un autre exemple notable est la valeur par défaut std::allocator lorsqu'il est utilisé par std::vector: les éléments sont construits en vector cours push_back, mais la mémoire est allouée dans les morceaux, de sorte qu'il pré-existe à l'élément de construction. Et donc, vector::erase devez détruire les éléments, mais pas nécessairement, il libère la mémoire (en particulier si de nouvelles push_back doivent arriver bientôt...).

C'est le "mauvais design" dans le strict sens de la programmation orientée objet (vous devez gérer des objets, pas de mémoire: le fait que les objets nécessitent de la mémoire est un "incident"), c'est une "bonne conception" dans "la programmation de bas niveau", ou dans les cas où la mémoire n'est pas prise à partir de la "boutique" par défaut operator new achète dans.

C'est un mauvais design, si cela se passe de façon aléatoire autour du code, il est bon, si cela se passe localement à des classes spécialement conçus à cette fin.

104voto

Dietmar Kühl Points 70604

Appeler le destructeur manuellement est nécessaire si l'objet a été construit à l'aide d'une surcharge forme d' operator new(), sauf lors de l'utilisation de la "std::nothrow" surcharges:

T* t0 = new(std::nothrow) T();
delete t0; // OK: std::nothrow overload

void* buffer = malloc(sizeof(T));
T* t1 = new(buffer) T();
t1->~T(); // required: delete t1 would be wrong
free(buffer);

En dehors de la gestion de la mémoire sur un assez faible niveau comme ci-dessus, l'appel des destructeurs explicitement, cependant, est un signe de mauvaise conception. Probablement, il est effectivement pas mal de design, mais carrément mauvais (oui, à l'aide d'un destructeur explicite suivie par un constructeur de copie d'appel à l'opérateur d'affectation est une mauvaise conception et susceptibles d'être mauvais).

Avec C++ 2011, il est une autre raison d'utiliser un destructeur explicite des appels: Lors de l'utilisation généralisée des syndicats, il est nécessaire de détruire explicitement l'objet courant et de créer un nouvel objet à l'aide de placement de nouveau lorsque vous changez le type de l'objet représenté. Aussi, lorsque l'union est détruit, il est nécessaire d'appeler explicitement le destructeur de l'objet courant si elle exige la destruction.

13voto

Jack Points 61503

Non, vous ne devez pas appeler explicitement, c'est parce qu'il serait appelé deux fois. Une fois pour le manuel de l'appel et une autre fois lors de l'étendue dans laquelle l'objet est déclaré se termine.

Par exemple.

{
  Class c;
  c.~Class();
}

Si vous avez vraiment besoin pour effectuer les mêmes opérations, vous devriez avoir une méthode distincte.

Il y a une situation spécifique dans laquelle vous souhaiterez peut-être appeler un destructeur sur un objet alloué dynamiquement avec un placement new mais le son n'est pas quelque chose que vous aurez jamais besoin.

9voto

Luchian Grigore Points 136646

Comme indiqué dans la FAQ, vous devez appeler le destructeur explicitement lorsque vous utilisez placement new .

C'est à peu près le seul moment où vous appelez explicitement un destructeur.

Je conviens cependant que cela est rarement nécessaire.

6voto

James Kanze Points 96599

Chaque fois que vous avez besoin de séparer l'allocation de l'initialisation, vous avez besoin d'un nouvel emplacement et d'un appel explicite du destructeur manuellement. Aujourd'hui, cela est rarement nécessaire, car nous avons les conteneurs standard, mais si vous devez implémenter un nouveau type de conteneur, vous en aurez besoin.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X