web-dev-qa-db-fra.com

Quand et comment dois-je utiliser la gestion des exceptions?

Je lis sur la gestion des exceptions. J'ai reçu des informations sur la gestion des exceptions, mais j'ai quelques questions:

  1. Quand lever une exception?
  2. Au lieu de lever une exception, pouvons-nous utiliser une valeur de retour pour indiquer l'erreur?
  3. Si je protège toutes mes fonctions par des blocs try-catch, cela ne réduira-t-il pas les performances?
  4. Quand utiliser la gestion des exceptions?
  5. J'ai vu un projet où chaque fonction de ce projet contenait un bloc try-catch (c'est-à-dire que le code à l'intérieur de la fonction entière est entouré d'un bloc try-catch). Est-ce une bonne pratique?
  6. Quelle est la différence entre try-catch et __try __except?
73
Umesha MS

Voici un guide assez complet sur les exceptions que je pense être une lecture incontournable:

Exceptions et gestion des erreurs - FAQ C++ ou C++ FAQ lite

En règle générale, lancez une exception lorsque votre programme peut identifier un problème externe qui empêche l'exécution. Si vous recevez des données du serveur et que ces données ne sont pas valides, lancez une exception. Vous manquez d'espace disque? Jetez une exception. Les rayons cosmiques vous empêchent d'interroger la base de données? Jetez une exception. Mais si vous obtenez des données non valides à l'intérieur de votre propre programme - ne lancez pas d'exception. Si votre problème vient de votre propre mauvais code, il est préférable d'utiliser ASSERT pour vous en protéger. La gestion des exceptions est nécessaire pour identifier les problèmes que le programme ne peut pas gérer et leur parler de l'utilisateur, car l'utilisateur peut les gérer. Mais les bogues dans votre programme ne sont pas quelque chose que l'utilisateur peut gérer, donc le plantage du programme ne dira pas beaucoup moins que "La valeur de answer_to_life_and_universe_and_everything n'est pas 42! Cela ne devrait jamais arriver !!!! 11" exception.

Attrapez une exception où vous pouvez faire quelque chose d'utile, comme afficher une boîte de message. Je préfère attraper une exception une fois à l'intérieur d'une fonction qui gère en quelque sorte l'entrée utilisateur. Par exemple, l'utilisateur appuie sur le bouton "Annihilate all hunams", et dans la fonction annihilateAllHunamsClicked (), il y a un bloc try ... catch pour dire "je ne peux pas". Même si l'annihilation de hunamkind est une opération complexe qui nécessite d'appeler des dizaines et des dizaines de fonctions, il n'y a qu'un seul essai ... attraper, car pour un utilisateur, c'est une opération atomique - un clic de bouton. Les contrôles d'exception dans chaque fonction sont redondants et moches.

De plus, je ne peux pas recommander assez de se familiariser avec RAII - c'est-à-dire, pour s'assurer que toutes les données initialisées sont détruites automatiquement. Et cela peut être réalisé en initialisant autant que possible sur la pile, et lorsque vous devez initialiser quelque chose sur le tas, utilisez une sorte de pointeur intelligent. Tout ce qui est initialisé sur la pile sera détruit automatiquement lorsqu'une exception est levée. Si vous utilisez des pointeurs muets de style C, vous risquez une fuite de mémoire lorsqu'une exception est levée, car il n'y a personne pour les nettoyer en cas d'exception (bien sûr, vous pouvez utiliser des pointeurs de style C en tant que membres de votre classe, mais assurez-vous qu'ils le sont) pris en charge dans destructeur).

80
Septagram

Les exceptions sont utiles dans diverses circonstances.

Premièrement, il existe certaines fonctions où le coût du calcul de la condition préalable est si élevé qu'il est préférable de simplement effectuer le calcul et d'interrompre avec une exception s'il est constaté que la condition préalable n'est pas remplie. Par exemple, vous ne pouvez pas inverser une matrice singulière, mais pour calculer si elle est singulière, vous calculez le déterminant qui est très coûteux: il peut être nécessaire de le faire de toute façon à l'intérieur de la fonction, alors essayez simplement d'inverser la matrice et rapportez une erreur si vous ne pouvez pas en lançant une exception. Il s'agit essentiellement d'une utilisation exception comme pré-condition négative.

Ensuite, il existe d'autres cas où votre code est déjà complexe et il est difficile de transmettre des informations d'erreur dans la chaîne d'appels. Cela est dû en partie au fait que C et C++ ont des modèles de structure de données cassés: il existe d'autres meilleures méthodes, mais C++ ne les prend pas en charge (comme l'utilisation de monades dans Haskell). Cette utilisation est fondamentalement je ne pouvais pas être dérangé de le faire correctement, donc je lèverai une exception: ce n'est pas la bonne façon mais c'est pratique.

Ensuite, il y a l'utilisation principale des exceptions: pour signaler lorsque des conditions préalables externes ou des invariants, tels que des ressources suffisantes comme la mémoire ou l'espace disque, ne sont pas disponibles. Dans ce cas, vous terminerez généralement le programme, ou une sous-section majeure de celui-ci, et l'exception est un bon moyen de transmettre des informations sur le problème. Les exceptions C++ ont été conçues pour signaler les erreurs qui empêchent le programme de continuer.

Le modèle de gestion des exceptions utilisé dans la plupart des langages modernes, y compris C++, est conn à casser. C'est beaucoup trop puissant. Les théoriciens ont maintenant développé de meilleurs modèles que le modèle "lancer quoi que ce soit" complètement ouvert et "peut-être et peut-être ne pas l'attraper". De plus, l'utilisation des informations de type pour classer les exceptions n'était pas une très bonne idée.

Donc, la meilleure chose que vous pouvez faire est lever les exceptions avec parcimonie, quand il y a une erreur réelle, et quand il n'y a pas d'autre moyen de la traiter et attraper les exceptions aussi près que possible du point de lancement.

12
Yttrill

Si votre problème vient de votre propre mauvais code, il est préférable d'utiliser ASSERT pour vous en protéger. La gestion des exceptions est nécessaire pour identifier les problèmes que le programme ne peut pas gérer et leur parler de l'utilisateur, car l'utilisateur peut les gérer. Mais les bogues dans votre programme ne sont pas quelque chose que l'utilisateur peut gérer, donc le plantage du programme ne dira pas grand-chose

Je ne suis pas d'accord avec cet aspect de la réponse acceptée . Une assertion n'est pas meilleure que de lever une exception. Si les exceptions ne convenaient qu'aux erreurs d'exécution (ou "problèmes externes"), qu'est-ce que std::logic_error pour?

Une erreur logique est presque par définition le type de condition qui empêche un programme de continuer. Si le programme est une construction logique et qu'une condition se produit en dehors du domaine de cette logique, comment peut-il continuer? Rassemblez vos entrées pendant que vous le pouvez, et jetez une exception!

Ce n'est pas comme s'il n'y avait pas d'antériorité. std::vector, pour n'en citer qu'un, lève une exception d'erreur logique, à savoir std::out_of_range. Si vous utilisez la bibliothèque standard et n'avez pas de gestionnaire de niveau supérieur pour intercepter les exceptions standard - ne serait-ce que pour appeler ce que () et exit (3) - alors vos programmes sont sujets à une interruption brutale silencieuse.

Une macro d'assertion est une garde beaucoup plus faible. Il n'y a pas de récupération. Sauf si vous n'utilisez pas de build de débogage, auquel cas il y a pas d'exécution. La macro d'assertion appartient à une époque où le calcul était de 6 ordres de grandeur plus lent qu'aujourd'hui. Si vous vous donnez la peine de tester les erreurs logiques, mais de ne pas utiliser ce test quand il compte, en production, vous feriez mieux d'avoir une grande confiance en votre code!

La bibliothèque standard prévoit des exceptions d'erreur logique et les utilise. Ils sont là pour une raison: parce que des erreurs logiques se produisent et sont exceptionnelles. Ce n'est pas parce que C comporte des assertions qu'il n'y a aucune raison de s'appuyer sur un mécanisme aussi primitif (et, sans doute, inutile), lorsqu'une exception gère le travail beaucoup mieux.

4
James K. Lowden

Meilleure lecture pour cela

La gestion des exceptions a fait beaucoup parler de la dernière décennie et demie. Cependant, malgré un consensus général sur la manière de gérer correctement les exceptions, une fracture d'utilisation continue d'exister. Une mauvaise gestion des exceptions est facile à repérer, facile à éviter et constitue une métrique de qualité de code (et de développeur) simple. Je sais que les règles absolues sont trop étroites ou exagérées, mais en règle générale, vous ne devriez pas utiliser try/catch

http://codebetter.com/karlseguin/2010/01/25/don-t-use-try-catch/

3
Sushan M

1.Une vérification des exceptions est incluse dans le code lorsqu'il existe une possibilité d'obtenir une exception en conséquence ou quelque part entre le problème.

2.Utilisez le bloc try-catch uniquement avec les cas où cela est nécessaire. L'utilisation de chaque bloc try-catch s'ajoute à une vérification de condition supplémentaire qui réduit certainement l'optimisation du code.

3.Je pense que _try_except est un nom de variable valide ....

2
user550830

La différence fondamentale est:

  1. on fait la gestion des erreurs pour vous.
  2. l'un est que vous faites le vôtre.

    • Par exemple, vous avez une expression qui pourrait faire 0 divide error. Utilisation de try catch 1. vous aidera en cas d'erreur. Ou vous avez besoin d'un if a==0 then.. dans 2.

    • Si vous n'essayez pas d'attraper l'exception, je ne pense pas que ce soit plus rapide, il suffit de contourner, si error s'est produit, ce sera threw vers un gestionnaire externe.

Se remettre soi-même signifie que le problème ne va pas plus loin, alors il a l'avantage de la vitesse dans de nombreux cas, mais pas toujours.

Suggère: Il suffit de se gérer quand c'est simple et dans un cas logique.

0
pinichi