Programmation C-C++/Les exceptions/Remontée des exceptions

Cours de C/C++
^
Les exceptions
Lancement et récupération d'une exception
Remontée des exceptions
Liste des exceptions autorisées pour une fonction
Hiérarchie des exceptions
Exceptions dans les constructeurs

Livre original de C. Casteyde

Les fonctions intéressées par les exceptions doivent les capter avec le mot clé catch comme on l'a vu ci-dessus. Elles peuvent alors effectuer tous les traitements d'erreurs que le C++ ne fera pas automatiquement. Ces traitements comprennent généralement le rétablissement de l'état des données manipulées par la fonction (dont, pour les fonctions membres d'une classe, les données membres de l'objet courant), ainsi que la libération des ressources non encapsulées dans des objets de classe de stockage automatique (par exemple, les fichiers ouverts, les connexions réseau, etc.).

Une fois ce travail effectué, elles peuvent, si elles le désirent, relancer l'exception, afin de permettre un traitement complémentaire par leur fonction appelante. Le parcours de l'exception s'arrêtera donc dès que l'erreur aura été complètement traitée. Bien entendu, il est également possible de lancer une autre exception que celle que l'on a reçue, comme ce peut être par exemple le cas si le traitement de l'erreur provoque lui-même une erreur.

Pour relancer l'exception en cours de traitement dans un gestionnaire d'exception, il faut utiliser le mot clé throw. La syntaxe est la suivante :

throw ;

L'exception est alors relancée, avec comme valeur l'objet que le compilateur a construit en interne pour propager l'exception. Les gestionnaires d'exception peuvent donc modifier les paramètres des exceptions, s'ils les attrapent avec une référence.

Si, lorsqu'une exception se produit dans un bloc try, il est impossible de trouver le bloc catch correspondant à la classe de cette exception, il se produit une erreur d'exécution. La fonction prédéfinie std::terminate est alors appelée. Elle se contente d'appeler une fonction de traitement de l'erreur, qui elle-même appelle la fonction abort de la bibliothèque C. Cette fonction termine en catastrophe l'exécution du programme fautif en générant une faute (les ressources allouées par le programme ne sont donc pas libérées, et des données peuvent être perdues). Ce n'est généralement pas le comportement désiré, aussi est-il possible de le modifier en changeant la fonction appelée par std::terminate.

Pour cela, il faut utiliser la fonction std::set_terminate, qui attend en paramètre un pointeur sur la fonction de traitement d'erreur, qui ne prend aucun paramètre et renvoie void. La valeur renvoyée par std::set_terminate est le pointeur sur la fonction de traitement d'erreur précédente. std::terminate et std::set_terminate sont déclaréee dans le fichier d'en-tête exception.

 Comme leurs noms l'indiquent, std::terminate et std::set_terminate sont déclarées dans l'espace de nommage std::, qui est réservé pour tous les objets de la bibliothèque standard C++. Si vous ne voulez pas à avoir à utiliser systématiquement le préfixe std:: devant ces noms, vous devrez ajouter la ligne « using namespace std; » après avoir inclus l'en-tête exception. Vous obtiendrez de plus amples renseignements sur les espaces de nommage dans le Chapitre 11.
À faire...link={{{link}}}

localiser

Exemple 9-2. Installation d'un gestionnaire d'exception avec set_terminate

modifier
#include <iostream>
#include <exception>

using namespace std;

void mon_gestionnaire(void)
{
    cout << "Exception non gérée reçue !" << endl;
    cout << "Je termine le programme proprement..."
         << endl;
    exit(-1);
}

int lance_exception(void)
{
    throw 2;
}

int main(void)
{
    set_terminate(&mon_gestionnaire);
    try
    {
        lance_exception();
    }
    catch (double d)
    {
        cout << "Exception de type double reçue : " <<
           d << endl;
    }
    return 0;
}