Quelle est la différence entre ces trois et comment dois-je terminer le programme en cas d'exception que je ne peux pas gérer correctement?
c++Il n'y a rien que nous puissions faire la source
3
Ce n'est pas un doublon, mais plutôt un sous-ensemble avec quelques bonnes réponses stackoverflow.com/questions/397075/... et il a également été étiqueté C ++!
Ellie Kesselman
std::abortest raisonnable si une exception ne peut pas être résolue dans un destructeur.
Mon conseil serait de ne pas en utiliser. Au lieu de cela, catchles exceptions que vous ne pouvez pas gérer main()et simplement à returnpartir de là. Cela signifie que vous avez la garantie que le déroulement de la pile se déroule correctement et que tous les destructeurs sont appelés. En d'autres termes:
int main(){try{// your stuff}catch(...){return1;// or whatever}}
@Neil: D'accord, mais les exceptions que le programme ne peut pas gérer doivent être signalées et relancées. Laissez l'application planter.
John Dibling
13
Pour vous assurer que la pile se déroule, vous devez toujours attraper en main. Mais je relancerais de la prise. Comme certains OS ont la capacité d'appeler automatiquement l'infrastructure de débogage si vous avez compilé en débogage.
Martin York
5
Les exceptions qui ne sont pas détectées même par un gestionnaire de niveau supérieur peuvent appeler une fonction de rapport système qui vide le processus et télécharge le rapport d'exception à l'attention des développeurs, comme le rapport d'erreurs Windows, les rapports d'erreurs Mac OS X et les journaux d'erreurs des applications iPhone.
JBRWilkinson
6
@John La raison pour laquelle cela me surprend est que, bien que cela soit parfaitement logique à la lumière de la façon dont les exceptions sont réellement implémentées, cela brise l'abstraction selon laquelle une exception "se propage dans la pile" jusqu'à ce qu'un gestionnaire approprié soit trouvé (ou terminer est appelé). Et les abstractions qui fuient, bien que souvent inévitables, sont nécessairement surprenantes lorsqu'elles sont rencontrées.
abort indique une fin "anormale" du programme et déclenche le signal POSIX SIGABRT, ce qui signifie que tout gestionnaire que vous avez enregistré pour ce signal sera appelé, bien que le programme se terminera toujours après les mots dans les deux cas. Habituellement, vous utiliserez abortdans un programme C pour quitter un cas d'erreur inattendu où l'erreur est susceptible d'être un bogue dans le programme, plutôt que quelque chose comme une mauvaise entrée ou une panne du réseau. Par exemple, vous pouvez abortsi une structure de données contient un pointeur NULL alors que cela ne devrait logiquement jamais se produire.
exit indique une fin "normale" du programme, bien que cela puisse toujours indiquer un échec (mais pas un bogue). En d'autres termes, vous pourriez exitavec un code d'erreur si l'utilisateur a donné une entrée qui n'a pas pu être analysée ou si un fichier n'a pas pu être lu. Un code de sortie de 0 indique le succès. exitappelle également éventuellement des gestionnaires avant de terminer le programme. Ceux-ci sont enregistrés avec les fonctions atexitet on_exit.
std :: terminate est ce qui est automatiquement appelé dans un programme C ++ lorsqu'il y a une exception non gérée. C'est essentiellement l'équivalent C ++ de abort, en supposant que vous signalez toutes vos erreurs exceptionnelles au moyen de la levée d'exceptions. Cela appelle un gestionnaire défini par la std::set_terminatefonction, qui par défaut appelle simplement abort.
En C ++, vous voulez généralement éviter d'appeler abortou exiten cas d'erreur, car il vaut mieux lever une exception et laisser le code plus haut dans la pile d'appels décider si la fin du programme est appropriée ou non. Que vous l'utilisiez ou non exitpour réussir est une question de circonstance - qu'il soit logique ou non de terminer le programme ailleurs que dans l'instruction return main.
std::terminatedevrait être considéré comme un outil de rapport d'erreurs de dernière minute, même en C ++. Le problème avec std::terminateest que le gestionnaire de terminate n'a pas accès à l'exception qui n'a pas été gérée, il n'y a donc aucun moyen de savoir ce que c'était. Il est généralement préférable d'emballer l'intégralité de main dans un try { } catch (std::exception& ex) { }bloc. Au moins, vous pouvez signaler plus d'informations sur les exceptions dérivées de std::exception(bien que, bien sûr, les exceptions qui ne dérivent pas de celles- std::exceptionci ne soient toujours pas gérées).
L'encapsulation du corps de mainin try { } catch(...) { }n'est pas beaucoup mieux que de définir un gestionnaire de terminaison, car encore une fois, vous n'avez pas accès à l'exception en question. Edit: Selon la réponse de Neil Butterworth, il y a un avantage dans le fait que la pile est déroulée dans ce cas, ce qui n'est (quelque peu surprenant) pas vrai pour une exception non gérée.
Pouvez-vous mettre à jour cette réponse avec des informations C ++ 11? Il semble qu'il existe maintenant des moyens d'obtenir l'exception dans le gestionnaire catch (...) et terminate.
Peu importe que vous puissiez obtenir l'exception actuelle, car vous ne pouvez pas l'inspecter. Tout ce que vous pouvez faire est de le relancer.
seattlecpp
2
@seattlecpp, vous pouvez le relancer et en attraper une référence, que vous pouvez ensuite inspecter
gpeche
16
std :: abort et std :: exit (et plus encore: std :: _ Exit, std :: quick_exit) ne sont que des fonctions de niveau inférieur. Vous les utilisez pour dire au programme ce que vous voulez qu'il fasse exactement: quels destructeurs (et si) appeler, quelles autres fonctions de nettoyage appeler, quelle valeur renvoyer, etc.
std :: terminate est une abstraction de plus haut niveau: elle est appelée (par le run-time ou par vous) pour indiquer qu'une erreur s'est produite dans le programme et que, pour une raison quelconque, il n'est pas possible de gérer en lançant une exception. La nécessité de cela se produit généralement lorsqu'une erreur se produit dans le mécanisme d'exception lui-même, mais vous pouvez l'utiliser à tout moment lorsque vous ne souhaitez pas que votre programme continue au-delà de l'erreur donnée. J'ai compilé la liste complète des situations où std :: terminate est appelé dans mon message. Ce n'est pas spécifié ce que fait std :: terminate, car vous en êtes le contrôle. Vous pouvez configurer le comportement en enregistrant toutes les fonctions. Les limitations que vous avez sont que la fonction ne peut pas retourner au site d'erreur et qu'elle ne peut pas quitter via une exception, mais techniquement, vous pouvez même démarrer votre pompe de message à l'intérieur. Pour la liste des choses utiles que vous pouvez faire à l'intérieur, consultez mon autre article .
En particulier, notez que std :: terminate est considéré comme un gestionnaire d'exceptions dans les contextes où std :: terminate est appelé en raison d'une exception levée qui n'a pas pu être gérée, et vous pouvez vérifier ce qu'était l'exception et l'inspecter en utilisant C ++ 11 en utilisant std :: rethrow_exception et std :: current_exception. Tout est dans mon post .
Est-il conseillé d'avoir un gestionnaire de nettoyage au cas où le programme se termine en raison de signaux système? Par exemple, un accès mémoire invalide conduit à la génération d'un signal SIGSEGV. Dans ce cas, est-il bon de laisser simplement le programme se terminer et d'avoir le fichier de base ou d'enregistrer un gestionnaire de signaux pour faire le nettoyage? Y a-t-il des problèmes de nettoyage tout en traitant les signaux système par rapport à un nettoyage en manipulant std :: terminate?
Si votre programme est multi-thread, alors l'appel exit()entraînera probablement un plantage car les std::threadobjets globaux / statiques seront tentés de se détruire sans quitter leurs threads.
Si vous souhaitez renvoyer un code d'erreur et quitter le programme (plus ou moins) normalement, appelez des quick_exit()programmes multithreads. Pour résiliation anormale (sans possibilité pour vous de spécifier le code d'erreur), abort()ou std::terminate()peut être appelé.
terminate () est automatiquement appelée lorsqu'une exception se produit qui ne peut pas être gérée. Par défaut, terminate () appelle abort (). Vous pouvez définir un handle personnalisé avec la fonction set_terminate ().
abort () envoie le signal SIGABRT.
exit () n'est pas nécessairement une mauvaise chose. Il réussit à quitter l'application et appelle les fonctions atexit () dans l'ordre LIFO. Je ne vois normalement pas cela dans les applications C ++, cependant, je le vois dans de nombreuses applications basées sur unix où il envoie un code de sortie à la fin. Habituellement, un exit (0) indique une exécution réussie de l'application.
std::abort
est raisonnable si une exception ne peut pas être résolue dans un destructeur.std::terminate
ces articles, consultez l'excellent blog C ++ d'Andrzej: akrzemi1.wordpress.com/2011/09/28/who-calls-stdterminate , akrzemi1.wordpress.com/2011/10/05/using-stdterminateRéponses:
Mon conseil serait de ne pas en utiliser. Au lieu de cela,
catch
les exceptions que vous ne pouvez pas gérermain()
et simplement àreturn
partir de là. Cela signifie que vous avez la garantie que le déroulement de la pile se déroule correctement et que tous les destructeurs sont appelés. En d'autres termes:la source
abort indique une fin "anormale" du programme et déclenche le signal POSIX SIGABRT, ce qui signifie que tout gestionnaire que vous avez enregistré pour ce signal sera appelé, bien que le programme se terminera toujours après les mots dans les deux cas. Habituellement, vous utiliserez
abort
dans un programme C pour quitter un cas d'erreur inattendu où l'erreur est susceptible d'être un bogue dans le programme, plutôt que quelque chose comme une mauvaise entrée ou une panne du réseau. Par exemple, vous pouvezabort
si une structure de données contient un pointeur NULL alors que cela ne devrait logiquement jamais se produire.exit indique une fin "normale" du programme, bien que cela puisse toujours indiquer un échec (mais pas un bogue). En d'autres termes, vous pourriez
exit
avec un code d'erreur si l'utilisateur a donné une entrée qui n'a pas pu être analysée ou si un fichier n'a pas pu être lu. Un code de sortie de 0 indique le succès.exit
appelle également éventuellement des gestionnaires avant de terminer le programme. Ceux-ci sont enregistrés avec les fonctionsatexit
eton_exit
.std :: terminate est ce qui est automatiquement appelé dans un programme C ++ lorsqu'il y a une exception non gérée. C'est essentiellement l'équivalent C ++ de
abort
, en supposant que vous signalez toutes vos erreurs exceptionnelles au moyen de la levée d'exceptions. Cela appelle un gestionnaire défini par lastd::set_terminate
fonction, qui par défaut appelle simplementabort
.En C ++, vous voulez généralement éviter d'appeler
abort
ouexit
en cas d'erreur, car il vaut mieux lever une exception et laisser le code plus haut dans la pile d'appels décider si la fin du programme est appropriée ou non. Que vous l'utilisiez ou nonexit
pour réussir est une question de circonstance - qu'il soit logique ou non de terminer le programme ailleurs que dans l'instruction returnmain
.std::terminate
devrait être considéré comme un outil de rapport d'erreurs de dernière minute, même en C ++. Le problème avecstd::terminate
est que le gestionnaire de terminate n'a pas accès à l'exception qui n'a pas été gérée, il n'y a donc aucun moyen de savoir ce que c'était. Il est généralement préférable d'emballer l'intégralité de main dans untry { } catch (std::exception& ex) { }
bloc. Au moins, vous pouvez signaler plus d'informations sur les exceptions dérivées destd::exception
(bien que, bien sûr, les exceptions qui ne dérivent pas de celles-std::exception
ci ne soient toujours pas gérées).L'encapsulation du corps de
main
intry { } catch(...) { }
n'est pas beaucoup mieux que de définir un gestionnaire de terminaison, car encore une fois, vous n'avez pas accès à l'exception en question. Edit: Selon la réponse de Neil Butterworth, il y a un avantage dans le fait que la pile est déroulée dans ce cas, ce qui n'est (quelque peu surprenant) pas vrai pour une exception non gérée.la source
std::current_exception()
std :: abort et std :: exit (et plus encore: std :: _ Exit, std :: quick_exit) ne sont que des fonctions de niveau inférieur. Vous les utilisez pour dire au programme ce que vous voulez qu'il fasse exactement: quels destructeurs (et si) appeler, quelles autres fonctions de nettoyage appeler, quelle valeur renvoyer, etc.
std :: terminate est une abstraction de plus haut niveau: elle est appelée (par le run-time ou par vous) pour indiquer qu'une erreur s'est produite dans le programme et que, pour une raison quelconque, il n'est pas possible de gérer en lançant une exception. La nécessité de cela se produit généralement lorsqu'une erreur se produit dans le mécanisme d'exception lui-même, mais vous pouvez l'utiliser à tout moment lorsque vous ne souhaitez pas que votre programme continue au-delà de l'erreur donnée. J'ai compilé la liste complète des situations où std :: terminate est appelé dans mon message. Ce n'est pas spécifié ce que fait std :: terminate, car vous en êtes le contrôle. Vous pouvez configurer le comportement en enregistrant toutes les fonctions. Les limitations que vous avez sont que la fonction ne peut pas retourner au site d'erreur et qu'elle ne peut pas quitter via une exception, mais techniquement, vous pouvez même démarrer votre pompe de message à l'intérieur. Pour la liste des choses utiles que vous pouvez faire à l'intérieur, consultez mon autre article .
En particulier, notez que std :: terminate est considéré comme un gestionnaire d'exceptions dans les contextes où std :: terminate est appelé en raison d'une exception levée qui n'a pas pu être gérée, et vous pouvez vérifier ce qu'était l'exception et l'inspecter en utilisant C ++ 11 en utilisant std :: rethrow_exception et std :: current_exception. Tout est dans mon post .
la source
quick_exit () !
Si votre programme est multi-thread, alors l'appel
exit()
entraînera probablement un plantage car lesstd::thread
objets globaux / statiques seront tentés de se détruire sans quitter leurs threads.Si vous souhaitez renvoyer un code d'erreur et quitter le programme (plus ou moins) normalement, appelez des
quick_exit()
programmes multithreads. Pour résiliation anormale (sans possibilité pour vous de spécifier le code d'erreur),abort()
oustd::terminate()
peut être appelé.Remarque: quick_exit () n'est pas pris en charge par MSVC ++ jusqu'à la version 2015.
la source
la source
terminate () est automatiquement appelée lorsqu'une exception se produit qui ne peut pas être gérée. Par défaut, terminate () appelle abort (). Vous pouvez définir un handle personnalisé avec la fonction set_terminate ().
abort () envoie le signal SIGABRT.
exit () n'est pas nécessairement une mauvaise chose. Il réussit à quitter l'application et appelle les fonctions atexit () dans l'ordre LIFO. Je ne vois normalement pas cela dans les applications C ++, cependant, je le vois dans de nombreuses applications basées sur unix où il envoie un code de sortie à la fin. Habituellement, un exit (0) indique une exécution réussie de l'application.
la source