Historique de la question :
Le mécanisme de gestion des exceptions a été introduit en C++ pour assurer un traitement des erreurs plus fiable et structuré, contrairement aux codes de retour. Au fil des ans, la syntaxe s'est élargie, et des spécificateurs comme noexcept ont été ajoutés pour contrôler l'annulation du lancement d'exceptions à partir de fonctions.
Problème :
Une mauvaise gestion des exceptions entraîne souvent des fuites de mémoire, un comportement indéfini ou des plantages d'applications. Si l'on ne prend pas en compte le lancement d'exceptions dans les constructeurs, les destructeurs ou lors de la manipulation de ressources, cela engendre un problème sérieux avec l'état du programme.
Solution :
La syntaxe de base — l'utilisation de try-catch. Les exceptions peuvent être de n'importe quel type, mais il est recommandé d'hériter des exceptions utilisateur de std::exception. Le mot-clé noexcept (C++11+) indique que la fonction ne doit pas lancer d'exceptions ; le lancer d'une exception depuis une fonction noexcept appelle std::terminate().
Exemple de code :
#include <iostream> #include <stdexcept> void func() noexcept(false) { throw std::runtime_error("Erreur !"); } int main() { try { func(); } catch(const std::exception& ex) { std::cout << ex.what(); } } }
Caractéristiques clés :
Est-il acceptable de lancer des exceptions dans un destructeur ?
Non, le lancement d'une exception dans un destructeur pendant le déroulement de la pile entraîne std::terminate(). Les exceptions dans le destructeur doivent être gérées à l'intérieur du destructeur lui-même.
Que se passe-t-il si une exception est lancée depuis une fonction noexcept ?
std::terminate sera appelé, le programme se terminera de manière abrupte. noexcept est un contrat strict.
Peut-on attraper des exceptions par valeur ? Quelles en sont les dangers ?
On peut attraper par valeur, mais l'objet est copié (object slicing). Il est recommandé d'utiliser const &.
Exemple de code :
try { throw std::out_of_range("err"); } catch (const std::exception& e) { /* ... */ }
Le code lançait des exceptions dans les destructeurs de ressources ; lors d'une terminaison abrupte, la pile était mal déroulée, et les ressources sont restées en fuite.
Avantages :
Inconvénients :
Les méthodes critiques étaient marquées noexcept, les destructeurs traitaient toutes les exceptions à l'intérieur. Des catch par référence étaient utilisés, toutes les erreurs étaient journalisées.
Avantages :
Inconvénients :