Je comprends que dans la plupart des cas, nous ne devrions pas appeler explicitement un destructeur. Cependant, j'ai vu un exemple tiré de C++ 11 Standard N3485, section 13.4.5, Arguments de modèle:
Un appel de destructeur explicite pour un objet dont le type est une spécialisation de modèle de classe peut spécifier explicitement les arguments de modèle. Exemple:
template<class T> struct A { ~A(); }; void f(A<int>* p, A<int>* q) { p->A<int>::~A(); // OK: destructor call q->A<int>::~A<int>(); // OK: destructor call }
Il me semble que nous pouvons appeler explicitement destructeur dans ce cas, pouvez-vous m'expliquer pourquoi? Que signifie l'appel de destructeur dans cet exemple? Pourquoi sont-ils raisonnables?
Une autre question:
Quels sont les cas où nous pouvons appeler explicitement des destructeurs lorsque nous implémentons placement delete
?
Merci.
EDIT: J'ai trouvé dans C++ FAQ que nous ne devrions pas appeler explicitement un destructeur sur une variable locale.
Il me semble que nous pouvons appeler explicitement destructeur dans ce cas, pouvez-vous m'expliquer pourquoi?
Voulez-vous dire pourquoi pouvons-nous? Parce que le langage autorise les appels de destructeur explicites sur n'importe quel objet. Comme vous le dites, cela donne généralement un comportement indéfini car la plupart des objets seront détruits d'une autre manière, et c'est un comportement indéfini de détruire quoi que ce soit deux fois (ou plus généralement d'y accéder après destruction). Mais cela signifie simplement que vous ne devez pas le faire, pas que le langage vous en empêchera.
Ou voulez-vous dire pourquoi voudrions-nous? Parce que c'est comme ça que vous détruisez un objet créé par placement new.
Que signifie l'appel de destructeur dans cet exemple?
Ils signifient tous deux la même chose et sont équivalents à p->~A()
; ils appellent le destructeur de l'objet. L'exemple montre que vous pouvez fournir des arguments de modèle ici si vous le souhaitez. Je ne sais pas pourquoi tu voudrais.
Quels sont les cas où nous pouvons appeler explicitement des destructeurs en plus de la suppression de l'emplacement?
Je pense que tu es autorisé à appeler un destructeur trivial (qui ne fait rien) quand tu veux; mais ça ne sert à rien. Je pense que la destruction de quelque chose créé avec un placement nouveau est la seule raison légitime de le faire.
Il me semble que nous pouvons appeler explicitement destructor dans ce cas, pourriez-vous m'expliquer pourquoi?
Parce que le langage lui permet d’appeler le destructeur de n’importe quel objet à tout moment (en supposant que vous y avez accès, par exemple, ce n’est pas un destructeur privé).
Que signifie cet appel de destructeur dans cet exemple?
Il invoque simplement le destructeur. Logiquement, cela signifie que l'objet est détruit et qu'il faut dès lors être considéré comme un déchet et qu'il ne doit pas être déréférencé ou utilisé. Techniquement, cela signifie que l’objet est dans l’état où le destructeur le laisse, ce qui, pour certains objets , peut être identique à la construction par défaut (mais vous ne devriez jamais, jamais compter sur cela).
Pourquoi sont-ils raisonnables?
Parfois, vous devez détruire des objets sans libérer leur mémoire. Cela se produit dans beaucoup de classes comme variant/any, divers systèmes de reliure de script et de réflexion, certaines implémentations de singleton, etc.
Par exemple, vous pouvez utiliser std::aligned_storage
Pour allouer un tampon à un objet, puis utiliser le placement nouveau pour construire un objet dans ce tampon. Vous ne pouvez pas appeler delete
sur cet objet car cela invoquera le destructeur et essaiera de libérer la mémoire qui le sauvegarde. Vous devez appeler explicitement le destructeur dans ce cas pour détruire correctement l'objet.
Quels sont les cas où nous pouvons appeler explicitement des destructeurs en plus de la suppression de placement?
Il n’existe pas vraiment de 'suppression de placement', à part l’opérateur correspondant pour placer nouveau (et tout appel à delete
invoquera implicitement le destructeur, à l’exception de ceux que le compilateur invoque pour une construction ayant échoué, par exemple votre 'suppression de placement 'notion).
Un exemple que j'ai donné ci-dessus. Un autre exemple est std::vector
. Vous pouvez appeler des fonctions membres comme pop_back()
. Ceci doit détruire le dernier élément du vecteur mais il ne peut pas utiliser delete
car la mémoire sauvegardant l'objet fait partie d'un tampon plus important qui doit être géré séparément. Il en va de même pour de nombreux autres conteneurs, tels que les tables de hachage à adresse ouverte, deque
, etc. Voici un exemple d'utilisation de template typename
Pour appeler explicitement le destructeur.
C'est une fonctionnalité dont l'utilisateur d'une bibliothèque aura très rarement besoin, mais l'implémenteur d'une bibliothèque de bas niveau comme la STL ou même certains frameworks d'application devra être utilisé ici et là.