Quand un gestionnaire de terminaison C ++ est-il la bonne chose (TM)?

Le standard C ++ fournit la fonction std::set_terminate qui vous permet de spécifier quelle fonction std::terminate doit réellement appeler. std::terminate ne devrait être appelé que dans des circonstances extrêmes, et les situations décrites par la norme lorsqu’elle est appelée sont graves (par exemple, une exception non capturée). Lorsque std::terminate est appelé, la situation semble analogue à un manque de mémoire – vous ne pouvez pas faire grand-chose de façon raisonnable.

J’ai lu qu’il peut être utilisé pour s’assurer que les ressources sont libérées – mais pour la majorité des ressources, cela devrait être géré automatiquement par le système d’exploitation à la fin du processus (par exemple, les descripteurs de fichier). Théoriquement, je peux voir un cas car si, par exemple, vous deviez envoyer un message spécifique à un serveur lorsque vous le quittez en raison d’un blocage. Mais la majorité du temps, le traitement du système d’exploitation devrait être suffisant.

Quand utiliser un gestionnaire de terminaison comme étant la bonne chose (TM)?

Mise à jour: les personnes intéressées par ce qui peut être fait avec des gestionnaires de terminaison personnalisés pourraient trouver cette astuce utile.

C’est juste optimiste:

mais pour la majorité des ressources, cela devrait être géré automatiquement par le système d’exploitation lorsque le processus se termine.

Les “ressources de fichiers” et la “mémoire” ne concernent que les seules ressources gérées automatiquement par le système d’exploitation. Pratiquement toutes les autres ressources (et si quelqu’un a une liste de ressources qui sont automatiquement gérées par les systèmes d’exploitation, j’adorerais cela) doivent être libérées manuellement par le système d’exploitation.

Votre meilleur pari est d’éviter de sortir en utilisant terminate () et d’essayer un arrêt contrôlé en forçant la stack à se dérouler correctement. Cela garantira que tous les destructeurs sont appelés correctement et que vos ressources sont libérées (via des destructeurs).

À propos de la seule chose que je ferais est de consigner le problème. Pour que, le cas échéant, je puisse revenir en arrière et corriger le code afin que cela ne se reproduise plus. J’aime que mon code détourne bien la stack pour la désallocation de ressources, mais c’est un avis que certaines personnes aiment bien les arrêts brusques lorsque les choses vont mal.

Ma liste de quand se termine est appelée:

En général, il est appelé lorsque le mécanisme de gestion des exceptions ne parvient pas à trouver un gestionnaire pour une exception levée. Quelques exemples spécifiques sont:

  • Une exception échappe à main ()
    • Remarque: Il est défini par implémentation si la stack est déroulée ici. Ainsi, j’attrape toujours en main puis en retordant (si je ne gère pas explicitement). Ainsi, je garantis le déroulement de la stack (sur toutes les plates-formes) tout en bénéficiant du mécanisme de gestion des exceptions du système d’exploitation.
  • Deux exceptions se propageant simultanément.
    • Une exception échappe à un desatructor alors qu’une autre exception se propage.
    • L’expression générée génère une exception
  • Une exception avant ou après main.
    • Si une exception échappe au constructeur / destructeur d’un object global.
    • Si une exception échappe au destructeur d’une variable statique de fonction. (c.-à-d. soyez prudent avec les constructeurs / destructeurs d’object statique non local)
    • Une exception échappe à une fonction enregistrée avec atexit ().
  • Un renvoi lorsque aucune exception ne se propage actuellement.
  • Une exception non listée échappe à une méthode / fonction qui possède une liste de spécificateurs d’exception.
    • via inattendu.

Semblable à une déclaration faite dans la réponse de Martin York , à propos de la seule chose que je fais dans un gestionnaire de terminaison personnalisé est de consigner le problème afin que je puisse identifier et corriger le code incriminé. C’est le seul cas où je trouve que l’utilisation d’un gestionnaire de terminaison personnalisé est la bonne chose .


Comme il est défini par l’implémentation que la stack soit ou non déroulée avant l’appel de std::terminate() , j’ajoute parfois du code pour générer une trace, afin de localiser une exception non interceptée 1 .

1) Cela semble fonctionner pour moi lorsque j’utilise GCC sur des plateformes Linux.

Je pense que la bonne question serait de savoir comment éviter les appels pour mettre fin au gestionnaire, plutôt que de savoir quand l’utiliser.