web-dev-qa-db-fra.com

Le bloc try-catch diminue-t-il les performances

Cette lien déclare,

Pour intercepter les exceptions, nous devons placer une partie du code sous inspection d'exception. Cela se fait en enfermant cette partie de code dans un bloc try. Lorsqu'une circonstance exceptionnelle survient dans ce bloc, une exception est levée qui transfère le contrôle au gestionnaire d'exceptions. Si aucune exception n'est levée, le code continue normalement et tous les gestionnaires sont ignorés.

Cela signifie-t-il que le fait d'avoir un bloc d'essai réduit les performances en raison de la tâche supplémentaire "d'inspection" pendant l'exécution?

33
bibbsey

TL; DR [~ # ~] non [~ # ~] , les exceptions sont généralement plus rapides sur le chemin non exceptionnel par rapport à la gestion du code d'erreur.


Eh bien, la remarque évidente est par rapport à quoi?

Par rapport à ne pas gérer l'erreur, cela diminue évidemment les performances; mais les performances valent-elles le manque de justesse? Je dirais que ce n'est pas le cas, alors supposons que vous vouliez dire par rapport à un code d'erreur vérifié avec une instruction if.

Dans ce cas, cela dépend. Il existe plusieurs mécanismes utilisés pour implémenter les exceptions. En fait, ils peuvent être implémentés avec un mécanisme si proche d'une instruction if qu'ils finissent par avoir le même coût (ou légèrement plus élevé).

En C++ cependant, tous les principaux compilateurs (gcc l'a introduit dans la série 4.x, MSVC l'utilise pour le code 64 bits) utilisent désormais le modèle d'exception à coût nul. Si vous lisez ceci document technique auquel Need4Sleep est lié, il est répertorié comme l'approche basée sur les tables. L'idée est que pour chaque point du programme qui peut vous lancer, vous enregistrez dans une table latérale quelques morceaux qui vous permettront de trouver la bonne clause catch. Honnêtement, c'est un peu plus compliqué au niveau de la mise en œuvre que les anciennes stratégies, mais le nom Zero Cost est dérivé du fait qu'il est free si aucune exception n'est levée. Comparez cela à une mauvaise prévision de branche sur un CPU. D'un autre côté, lorsqu'une exception est levée, la pénalité est énorme parce que la table est stockée dans une zone froide (nécessite donc probablement un aller-retour vers RAM ou pire) ... mais les exceptions sont exceptionnelles, non?

Pour résumer, avec les compilateurs C++ modernes, les exceptions sont plus rapides que les codes d'erreur, au prix de binaires plus importants (en raison des tables statiques).


Par souci d'exhaustivité, il existe une 3ème alternative: l'avortement. Au lieu de propager une erreur via l'état ou l'exception, il est possible d'interrompre le processus à la place. Cela ne convient que dans un nombre restreint de situations, mais il optimise mieux que les deux alternatives.

69
Matthieu M.

Jetez un oeil à la section 5.4 de projet de rapport technique sur les performances C++ qui concerne spécifiquement les frais généraux des instructions try-catch en c ++.

Un petit extrait de la section:

5.4.1.1.2 Temps supplémentaire de l'approche "Code"

• On entry to each try-block
    ♦ Commit changes to variables enclosing the try-block
    ♦ Stack the execution context 
    ♦ Stack the associated catch clauses 
• On exit from each try-block
    ♦ Remove the associated catch clauses 
    ♦ Remove the stacked execution context 
• When calling regular functions 
    ♦ If a function has an exception-specification, register it for checking 
• As local and temporary objects are created 
    ♦ Register each one with the current exception context as it is created 
• On throw or re-throw 
    ♦ Locate the corresponding catch clause (if any) – this involves some runtime check (possibly resembling RTTI checks) 
    If found, then: 
    destroy the registered local objects 
    check the exception-specifications of the functions called in-between 
    use the associated execution context of the catch clause 
    Otherwise: 
    call the terminate_handler6
6

Ça dépend. Pour la gestion des exceptions, le compilateur doit faire quelque chose - sinon il ne pourrait pas faire le déroulement de la pile et autres. Cela signifie que la gestion des exceptions diminue les performances, même si l'exception n'est pas levée. Combien - cela dépend de la mise en œuvre de vos compilateurs.

D'un autre côté, vous devez vous poser des questions: si vous insérez vous-même votre code de gestion des erreurs, serait-ce vraiment plus rapide (mesurez-le - ne le devinez pas). Peut-il faire la même chose que les exceptions (les exceptions ne peuvent pas être ignorées par le client - les codes d'erreur peuvent - et ils peuvent faire un stackupwinding que les codes d'erreur ne peuvent pas). En outre, le code peut être écrit pour être plus maintenable avec des exceptions.

Bref: à moins que votre code ne soit très très très très très critique en temps, utilisez des exceptions. Même si vous décidez contre eux: mesurez d'abord. Une exception à la règle: c'est une mauvaise idée de lancer des exceptions au-delà des limites du module ou dans un destructeur.

2
Tobias Langner

Cela dépend vraiment du compilateur spécifique.

Si le compilateur préfère considérer la levée d'exceptions comme une condition vraiment exceptionnelle, vous pouvez implémenter un schéma où, en l'absence d'exception, vous avez zéro surcharge mais cela, à son tour, coûtera plus de temps en cas d'exception et/ou plus de taille de code .

Pour implémenter une approche sans surcharge, vous pouvez remarquer qu'en C++, vous ne pouvez pas modifier dynamiquement le code, donc une fois que vous savez quel est le cadre de la pile et l'adresse de retour, il est fixe quels sont les objets qui doivent être détruits en cas de déroulement ou s'il y a un section de code de gestion des exceptions. Le code pour lever une exception pourrait donc vérifier une table globale de tous les sites d'appels de fonction pour décider ce qui doit être fait.

De l'autre côté, vous pouvez accélérer le lancement d'exceptions en préparant la liste des objets à détruire explicitement et l'adresse du code de gestion des exceptions pendant l'exécution normale. Cela rendra le code normal plus lent, mais la gestion des exceptions plus rapide et je dirais aussi que le code est un peu plus petit.

Malheureusement, il n'y a pas de moyen standard en C++ pour abandonner complètement le support des exceptions, donc quelque chose doit être payé à cette possibilité: la bibliothèque standard lève des exceptions et tout code qui appelle du code inconnu (par exemple en utilisant un pointeur de fonction ou en appelant une méthode virtuelle) doit être prêt à gérer une exception.

2
6502

Je recommanderais d'ajouter try catch dans les fonctions qui font l'allocation de mémoire, la suppression, l'appel à d'autres fonctions complexes, etc. En fait, en termes de performances, try catch ajoute un peu de surcharge.

Mais compte tenu du mérite d'attraper les exceptions inconnues, il est très utile. Les bonnes pratiques de programmation recommandent toujours d'ajouter une sorte de gestion des exceptions dans votre code, sauf si vous êtes un programmeur exceptionnel.

Je me demande pourquoi vous êtes si préoccupé par un petit problème de performances que l'ensemble du programme étant bloqué avec une exception.

1
CodeRider