Gestion des erreurs en C++ : try, catch et approches modernes

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Gestion des erreurs en C++ : de try/catch à RAII et noexcept



La fiabilité d'un programme dépend directement de sa réaction face aux situations imprévues. En C++, le mécanisme principal pour cela est les exceptions. Dans cet article, nous allons analyser la construction classique try/catch/throw, ainsi que les approches alternatives et modernes : RAII, noexcept et la gestion des erreurs sans exceptions.



1. Mécanisme de base : try, catch, throw



Une exception est un objet qui est « lancé » (throw) lors de l'apparition d'une erreur. Le programme peut l'intercepter (catch) et exécuter des actions correctives sans interrompre complètement le travail.



Syntaxe

#include <iostream>#include <stdexcept>

double divide(double a, double b) { if (b == 0.0) { throw std::runtime_error("Division par zéro !"); } return a / b;}

int main() { try { double result = divide(10.0, 0.0); std::cout << "Résultat : " << result << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Erreur : " << e.what() << std::endl; } return 0;}


Règles de fonctionnement

  • throw — crée une copie de l'objet et transfère le contrôle au gestionnaire.
  • try — bloc de code où des exceptions peuvent survenir.
  • catch — intercepte l'exception par type. On peut spécifier plusieurs blocs catch.
  • Si l'exception n'est pas interceptée, std::terminate() est appelé.


Interception par classe de base

Toutes les exceptions standard héritent de std::exception. On peut donc écrire un gestionnaire universel :

try {    // code} catch (const std::exception& e) {    std::cerr << "Erreur standard : " << e.what() << std::endl;} catch (...) {    std::cerr << "Exception inconnue" << std::endl;}

Le bloc catch (...) attrape absolument toutes les exceptions, mais sans accès à l'objet.



2. Exceptions dans les constructeurs et destructeurs



Constructeurs

Si un constructeur lève une exception, l'objet est considéré comme non créé, et le destructeur pour celui-ci n'est pas appelé. Ceci est important pour la gestion des ressources. Exemple :

class Resource {public:    Resource() {        std::cout << "Ressource allouée" << std::endl;        throw std::runtime_error("Erreur d'initialisation");    }    ~Resource() {        std::cout << "Ressource libérée" << std::endl;    }};

int main() { try { Resource r; } catch (...) { std::cout << "Exception interceptée" << std::endl; } // Le destructeur de Resource NE sera PAS appelé ! return 0;}


Destructeurs

Lever des exceptions depuis un destructeur est une mauvaise pratique. Si un destructeur est appelé pendant le déroulement de la pile (stack unwinding) et qu'il lève une nouvelle exception, le programme se termine anormalement. Écrivez toujours les destructeurs comme noexcept (par défaut, ils le sont déjà).



3. RAII — gestion automatique des ressources

L'idiome RAII (Resource Acquisition Is Initialization) est la clé d'un code sûr. La ressource (mémoire, fichier, mutex) est acquise dans le constructeur et libérée dans le destructeur. Si une exception se produit, les destructeurs de tous les objets créés sont appelés automatiquement (stack unwinding), et les ressources sont libérées.



Exemple avec le pointeur intelligent std::unique_ptr :

#include <memory>#include <iostream>

void process() { auto ptr = std::make_unique<int>(42); // Si une exception survient ici, // unique_ptr libérera automatiquement la mémoire throw std::runtime_error("Erreur dans proc");

Blogs

Book Recommendations