Le système d'exceptions en C++ est basé sur le mécanisme try-catch et le mot-clé throw. Lorsqu'une situation exceptionnelle se produit (par exemple, une erreur de ressource, une violation d'invariant), une exception est déclenchée à l'intérieur du bloc try via l'opérateur throw. Les opérations de recherche d'un gestionnaire approprié (catch) se font en affichant la pile jusqu'au premier type correspondant.
Détails importants :
std::exception).noexcept.Conception :
catch(const std::exception& e).Exemple de code :
#include <iostream> #include <stdexcept> void mayFail(bool fail) { if (fail) throw std::runtime_error("Erreur de traitement"); } int main() { try { mayFail(true); } catch (const std::exception& ex) { std::cout << "Exception capturée : " << ex.what() << std::endl; } }
Que se passe-t-il si une exception est lancée depuis un destructeur pendant que l'on transmet une autre exception en remontant la pile ?
Réponse : Cela entraînera la terminaison anormale du programme via std::terminate(), car la génération d'une nouvelle exception (double exception) n'est pas autorisée pendant le traitement d'une exception, sinon cela perturbe le déroulement de la pile.
Exemple :
struct CrashOnDestruct { ~CrashOnDestruct() noexcept(false) { throw std::runtime_error("Erreur dans le destructeur !"); } }; void func() { CrashOnDestruct obj; throw std::logic_error("Traitement de l'erreur"); } int main() { try { func(); } catch (...) { } } // Terminera via std::terminate()
Histoire
Dans une grande application financière, des exceptions étaient lancées depuis le destructeur d'une classe d'enveloppe autour d'une base de données. Une des transactions critiques, lorsqu'une erreur survenait, déclenchait une exception, et lors du défilement, le destructeur était appelé, ce qui lançait également une erreur. L'ensemble de l'application se terminait de manière anormale, perdant le travail des utilisateurs. Les développeurs ont dû rapidement remplacer throw dans les destructeurs par des enregistrements de logs et un traitement correct.
Histoire
Un microservice traitait les exceptions du type : catch(std::exception). Un des threads lançait des exceptions de types utilisateurs (non dérivés de std::exception). Ces erreurs n'étaient pas interceptées, ce qui provoquait une rupture inattendue de la connexion et une fuite de mémoire.
Histoire
L'absence de spécificateur noexcept dans les méthodes de déplacement des conteneurs a conduit à ce que la bibliothèque standard utilise une copie lente au lieu d'une opération de déplacement rapide ; un échec significatif en termes de performances n'a été identifié qu'au cours des tests de charge.