Namespaces
Variants

Exceptions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

La gestion des exceptions offre un moyen de transférer le contrôle et les informations d'un point de l'exécution d'un programme vers un gestionnaire associé à un point précédemment passé par l'exécution (en d'autres termes, la gestion des exceptions transfère le contrôle vers le haut de la pile d'appels).

L'évaluation d'une throw expression va lancer une exception. Les exceptions peuvent également être lancées dans d'autres contextes .

Pour qu'une exception soit capturée, l'expression throw doit être à l'intérieur d'un try block , et le try block doit contenir un handler qui correspond au type de l'objet exception.

Lors de la déclaration d'une fonction, la ou les spécifications suivantes peuvent être fournies pour limiter les types d'exceptions qu'une fonction peut lever :

(jusqu'à C++17)
(depuis C++11)

Les erreurs qui surviennent pendant la gestion des exceptions sont traitées par std::terminate et std::unexpected (jusqu'en C++17) .

Table des matières

Utilisation

Bien que throw puisse être utilisé pour transférer le contrôle vers un bloc de code arbitraire plus haut dans la pile d'exécution, pour des raisons arbitraires (similaire à std::longjmp ), son utilisation prévue est la gestion d'erreurs.

Gestion des erreurs

Lever une exception est utilisée pour signaler des erreurs depuis des fonctions, où les "erreurs" sont généralement limitées uniquement aux cas suivants [1] [2] [3] :

  1. Les manquements aux postconditions, tels que l'incapacité à produire un objet de retour valide.
  2. Les manquements aux préconditions d'une autre fonction qui doit être appelée.
  3. (pour les fonctions membres non privées) Les manquements à (r)établir un invariant de classe.

En particulier, cela implique que les échecs des constructeurs (voir aussi RAII ) et la plupart des opérateurs doivent être signalés en lançant des exceptions.

De plus, les fonctions dites à contrat large utilisent les exceptions pour indiquer des entrées inacceptables, par exemple, std::basic_string::at n'a pas de préconditions, mais lance une exception pour indiquer un indice hors limites.

Sécurité des exceptions

Après qu'une condition d'erreur est signalée par une fonction, des garanties supplémentaires peuvent être fournies concernant l'état du programme. Les quatre niveaux suivants de garantie d'exception sont généralement reconnus [4] [5] [6] , qui sont des sur-ensembles stricts les uns des autres :

  1. Garantie d'exception Nothrow (ou nofail) — la fonction ne lève jamais d'exceptions. Nothrow (les erreurs sont signalées par d'autres moyens ou masquées) est attendu des destructeurs et autres fonctions qui peuvent être appelées pendant le déroulement de la pile. Les destructeurs sont noexcept par défaut. (depuis C++11) Nofail (la fonction réussit toujours) est attendu des swaps, move constructors , et autres fonctions utilisées par celles qui fournissent la garantie d'exception forte.
  2. Garantie d'exception forte — Si la fonction lève une exception, l'état du programme est restauré à l'état juste avant l'appel de la fonction (par exemple, std::vector::push_back ).
  3. Garantie d'exception basique — Si la fonction lève une exception, le programme est dans un état valide. Aucune ressource n'est fuitée, et tous les invariants des objets sont intacts.
  4. Aucune garantie d'exception — Si la fonction lève une exception, le programme peut ne pas être dans un état valide : des fuites de ressources, une corruption de mémoire, ou d'autres erreurs destructrices d'invariants peuvent s'être produites.

Les composants génériques peuvent, en outre, offrir une garantie d'exception-neutre : si une exception est levée par un paramètre de modèle (par exemple par la Compare fonction objet de std::sort ou par le constructeur de T dans std::make_shared ), elle est propagée, inchangée, à l'appelant.

Objets d'exception

Bien que des objets de tout type complet et des pointeurs cv vers void puissent être lancés comme objets d'exception, toutes les fonctions de la bibliothèque standard lancent des objets anonymes par valeur, et les types de ces objets sont dérivés (directement ou indirectement) de std::exception . Les exceptions définies par l'utilisateur suivent généralement ce modèle. [7] [8] [9]

Pour éviter la copie inutile de l'objet d'exception et le slicing d'objet, la meilleure pratique pour les gestionnaires est de capturer par référence. [10] [11] [12] [13]

Notes

Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_constexpr_exceptions 202411L (C++26) constexpr exceptions

Liens externes

  1. H. Sutter (2004) "Quand et comment utiliser les exceptions" dans Dr. Dobb's
  2. H. Sutter, A. Alexandrescu (2004), "C++ Coding Standards", Item 70
  3. C++ Core Guidelines I.10 : Utilisez les exceptions pour signaler l'échec d'une tâche requise
  4. B. Stroustrup (2000), "The C++ Programming Language" Annexe E
  5. H. Sutter (2000) "Exceptional C++"
  6. D. Abrahams (2001) "Sûreté des exceptions dans les composants génériques"
  7. D. Abrahams (2001) "Gestion des erreurs et des exceptions"
  8. isocpp.org Super-FAQ "Que dois-je lancer ?"
  9. C++ Core Guidelines E.14 : Utilisez des types définis par l'utilisateur conçus à cet effet comme exceptions (pas des types intégrés)
  10. C++ Core Guidelines E.15 : Lancez par valeur, capturez les exceptions d'une hiérarchie par référence
  11. S. Meyers (1996) "More Effective C++" Item 13
  12. isocpp.org Super-FAQ "Que dois-je capturer ?"
  13. H. Sutter, A. Alexandrescu (2004) "C++ Coding Standards" Item 73