Question

Je m'attendais à ce que A :: ~ A () soit appelé dans ce programme, mais ce n'est pas:

#include <iostream>

struct A {
  ~A() { std::cout << "~A()" << std::endl; }
};

void f() {
  A a;
  throw "spam";
}

int main() { f(); }

Cependant, si je change la dernière ligne en

int main() try { f(); } catch (...) { throw; }

alors A :: ~ A () est appelé.

Je compile avec "Compilateur d'optimisation C / C ++ Microsoft (R) 32 bits, version 14.00.50727.762 pour 80x86". à partir de Visual Studio 2005. La ligne de commande est cl / EHa my.cpp .

Le compilateur at-il raison comme d’habitude? Que dit la norme à ce sujet?

Était-ce utile?

La solution

Le destructeur n'est pas appelé car terminate () pour l'exception non gérée est appelée avant que la pile ne soit déroulée.

Les détails spécifiques de ce que la spécification C ++ dit sont en dehors de mes connaissances, mais une trace de débogage avec gdb et g ++ semble en tenir compte.

Selon le norme standard , section 15.3 puce 9:

9 If no matching handler is found in a program, the function terminate()
  (_except.terminate_)  is  called.  Whether or not the stack is unwound
  before calling terminate() is implementation-defined.

Autres conseils

La spécification du langage C ++ indique: Le processus d’appel des destructeurs pour les objets automatiques construits sur le chemin d’un bloc try à une expression-throw est appelé "pile de déroulement". Votre code d'origine ne contient pas de bloc try, c'est pourquoi le déroulement de la pile ne se produit pas.

J'ai également supposé que le compilateur ne générait pas le code relatif à "un" comme il n'est pas référencé mais que, néanmoins, ce n'est pas le bon comportement car le destructeur fait quelque chose qui doit être exécuté.

Alors, j’ai essayé dans VS2008 / vc9 (+ SP1), Debug and Release et ~ A est appelé après le lancement de l’exception, en sortant de f () - c’est le bon comportement, si j’ai raison.

Maintenant, je viens d'essayer avec VS2005 / vc8 (+ SP1) et c'est le même comportement.

J'ai utilisé des points d'arrêt pour en être sûr. Je viens de vérifier auprès de la console et j’ai le " ~ A " message aussi. Peut-être que vous vous êtes trompé ailleurs?

Désolé, je n'ai pas de copie de la norme sur moi.
Je voudrais vraiment une réponse définitive à cette question, de sorte que quelqu'un avec une copie de la norme veuille partager un chapitre et des vers sur ce qui se passe:

D'après ce que j'ai compris, terminer n'est appelé que si et seulement si:

  • Le mécanisme de gestion des exceptions ne trouve pas de gestionnaire pour une exception levée.
    Voici des cas plus spécifiques:
    • Lors du déroulement de la pile, une exception échappe à un destructeur.
    • Une expression renvoyée, une exception échappe au constructeur.
    • Une exception échappe au constructeur / destructeur d'un statique non local (ie global)
    • Une exception échappe à une fonction enregistrée avec atexit ().
    • Une exception échappe à main ()
  • Essayer de relancer une exception lorsqu'aucune exception ne se propage actuellement.
  • Une exception inattendue échappe à une fonction avec des spécificateurs d'exception (via inattendu)

Cette question est facile à rechercher sur Google. Je partage donc ma situation ici.

Assurez-vous que votre exception ne traverse pas la limite extern " "C" ou n'utilisez pas l'option MSVC / EHs (Activer les exeptions C ++ = Oui avec les fonctions Extern C (/ EHs))

Dans le deuxième exemple, le dtor est appelé lorsqu'il quitte le bloc try {}.

Dans le premier exemple, le dtor est appelé lorsque le programme s’arrête après avoir quitté la fonction main () - à l’époque où cout a peut-être déjà été détruit.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top