web-dev-qa-db-fra.com

En désactivant les exceptions C ++, comment puis-je faire terminer std :: throw () immédiatement?

Ce programme C++ est un script CGI, je n'ai aucune envie de traiter les exceptions. Je préfère obtenir une amélioration marginale des performances et laisser le système d'exploitation (Linux) gérer le nettoyage après la fin du processus.

J'utilise la bibliothèque standard C++ et je veux que n'importe quelle fonction die comme en Perl: chaque fois qu'elle lève une exception. Sans déroulement, ou exécution tout autre code dans mon processus.

Comment fonctionne -fno-exceptions? Si je n'ai aucune prise du tout dans mon code, et que je fais comme si les exceptions n'existaient pas. mais je fais utiliser la bibliothèque std :: c ++ qui peut throw ()?

37
unixman83

Option n ° 1: ne saisissez jamais d'exceptions.

Les exceptions n'ont pas beaucoup de frais généraux lorsqu'elles ne sont pas jetées ou prises; si vous lancez et n'êtes pas prêt à attraper, eh bien, vous faites quand même mourir, donc l'impact sur les performances à ce stade est trivial. Notez également que le déroulement de la pile ne sera pas effectué si une exception n'est pas gérée; le programme se terminera simplement sans effectuer le déroulement de la pile.

Il est important de noter que, dans G ++, les exceptions n'ont presque pas de surcharge lorsqu'elles ne sont pas réellement levées. G ++ génère des informations supplémentaires suffisantes pour retracer l'exécution du programme à travers la pile, et du code supplémentaire pour invoquer des destructeurs, etc. Par conséquent, vous ne devriez pas voir de différence de performances entre le code avec des exceptions activées mais non utilisées et le code avec des exceptions désactivées (quel que soit le mécanisme).

Option n ° 2: passez -fno-exceptions.

Cet indicateur demande à G ++ de faire deux choses :

  1. Toute la gestion des exceptions dans les bibliothèques STL est supprimée; les lancers sont remplacés par des appels à abort()
  2. La pile déroule les données et le code est supprimé. Cela économise un peu d'espace de code et peut rendre l'allocation des registres légèrement plus facile pour le compilateur (mais je doute que cela ait beaucoup d'impact sur les performances). Notamment, cependant, si une exception est levée et que la bibliothèque essaie de se dérouler via le code -fno-exceptions, Elle s'interrompra à ce stade, car il n'y a pas de données de déroulement.

Cela transformera efficacement toutes les exceptions en abort() s, comme vous le souhaitez. Notez cependant que vous ne serez pas autorisé à throw - tout throws ou catchs réel dans votre code entraînera une erreur au moment de la compilation.

Option n ° 3: (non portable et non recommandé!) Hook __cxa_allocate_exception.

Les exceptions C++ sont implémentées à l'aide (entre autres) des fonctions de bibliothèque interne __cxa_allocate_exception et __cxa_throw. Vous pouvez implémenter une bibliothèque LD_PRELOAD qui accroche ces fonctions pour abandonner ():

void __cxa_allocate_exception() { abort(); }
void __cxa_throw() { abort(); }

AVERTISSEMENT: il s'agit d'un horrible hack. Cela devrait fonctionner sur x86 et x86-64, mais je le déconseille fortement. Notamment, cela n'améliorera pas réellement les performances ou n'économisera pas d'espace de code, comme pourrait le faire -fno-exceptions. Cependant, il autorisera la syntaxe throw, tout en transformant throws en abort() s.

69
bdonlan

-fno-exceptions Transforme tous les lancements de bibliothèque standard en un appel à std::abort() . Cela gère la partie que vous ne pouvez pas modifier directement, le reste est de ne pas les utiliser du tout dans votre code.

Bien sûr, je doute vraiment de votre justification en faisant cela. Vous ne "perdez" les performances que lorsque vous lancez réellement, et vous jetez une partie importante et utile du langage.

20
GManNickG

Dans le cas où quelqu'un tomberait sur cette question, je voudrais corriger ce @GManNickG et ( https://stackoverflow.com/a/7249460/157344 ) et @bdonlan ( https: //stackoverflow.com/a/7249442/157344 ) a dit dans ses réponses. Malheureusement, la partie sur "-fno-exception" supprimant tout le code de gestion des exceptions et transformant tous les lancers en abandons est incorrecte. Eh bien - partiellement faux. Cela est vrai lorsque vous compilez la bibliothèque en question (libstdc ++ v3) avec cet indicateur, mais pas vrai si vous utilisez cette bibliothèque (en tant que .a ou .so ou .dll ou autre) dans votre propre code compilé avec cet indicateur . Dans ce dernier cas, le code de gestion des exceptions dans VOTRE code est interdit, mais tous les appels à la gestion des exceptions à l'intérieur de la bibliothèque restent (car la bibliothèque a été compilée [~ # ~] sans [~ # ~ ] cet indicateur, avec des exceptions activées), donc si vous utilisez new alors votre exécutable [~ # ~] sera [~ # ~ ] ont un code de gestion des exceptions - la seule différence est que vous ne pouvez rien à propos de ces exceptions avec une catch() (ce qui est interdit dans votre code), donc tous les lancers finissent effectivement comme abort(), mais uniquement parce que personne ne les attrape.

13
Freddie Chopin

Citation:

Ce programme C++ est un script CGI, je n'ai aucune envie de gérer les exceptions.

  • Alors ne le fais pas. Facile. L'exception arrivera très rapidement en haut de la pile.

Mais je vous exhorte à le faire. Cela signifie que vous pensez aux choses qui peuvent mal tourner.

9
Ed Heal

Ne les attrapez pas n'importe où dans votre code. Dans ce cas, un gestionnaire de terminaison sera appelé et votre programme "plantera".

1
user405725