[Accueil] - [Plan du site] - [Rechercher] - [ C O L R T S P ]  

 
Gérer une hierarchie d’exceptions en C++
Une manière, parmi d’autres, d’éviter trop de travail 

par nojhan le 11 avril 2006

Le C++ permet de gérer des hierarchies d’exceptions et la plupart des compilateurs permettent d’obtenir des informations sur le code source au moment de la compilation. Comment concilier les deux tout en évitant le moindre effort ?

L’avantage d’une hierarchie de classes d’exceptions réside dans la capacité de gérer différents niveaux d’erreurs. La librairie standard fournie les bases d’une telle hierarchie, mais ne permet en général que la gestion d’une seule chaine de caractère d’explications.

Or, dans un projet un peu conséquent, il est pratique d’avoir des informations sur l’endroit d’où est parti l’exception, et ce au moment de l’éxecution.

La plupart des compilateurs modernes permettent l’utilisation des macros __FILE__, __FUNCTION__ et __LINE__, qui renvoient respectivement le nom du fichier, la fonction et le numéro de ligne de l’endroit où elles sont placées.

Comment, alors, gérer une hierarchie d’exceptions en utilisant ces informations, sans avoir à taper des définitions de 10 lignes et des appels de 100 caractères ?

Classe d’exception de base

On commence par définir une classe d’exception de base, qui embarque des attributs pour les informations du compilateur :

class Exception
{
protected:
   string name;
   string description;
   string function;
   string file;
   int line;

public:
   Exception  ( const string & desc, const string & func, const string & f, const int l ) : description(desc), function(func), file(f), line(l) {};

   string what();
};

Deux méthodes ici : le constructeurs, qui initialise les attributs et une méthode pour afficher une description complète de l’exception.

La méthode what ayant un code du genre :

string Exception_oMetah::what()
{
   ostringstream msg;
   msg << description << "."
       << " (<" << name << ">"
       << " error in function <" << function
       << ">, in file <" << file << ">"
       << ", at line " << line << ")"
       << endl;

   return msg.str();
}

Classes dérivées

Il faut ensuite définir des classes d’exceptions héritants de la classe de base. Ici, un problème se pose quant à leur déclaration, qui doit définir un nouveau constructeur (avec le même prototype) faisant appel au constructeur de la classe héritée. Autant dire que ce n’est pas très plaisant à taper, à maintenir ou à lire...

Puisque le prototype du constructeur est appelé à être toujours le même, une macro s’impose :
#define EXCEPTION_DECLARATION(Current,Super) class Current : public Super {public: Current ( const string & desc, const string & func="?", const string & f="?", const int l=-1 ) : Super (desc,func,f,l) {name = #Current;} }

Celle-ci permet de déclarer la classe complète, en spécifiant simplement son nom et le nom de la classe mère. On ajoute également des valeurs d’initialisation des attributs par défaut.

On l’appelle très simplement, sur une seule ligne, ce qui permet de mettre en valeur la hierarchie des classes :

EXCEPTION_DECLARATION(Exception_Size,Exception);
   EXCEPTION_DECLARATION(Exception_Size_Index,Exception_Size);
     EXCEPTION_DECLARATION(Exception_Size_Index_OutOfBounds,Exception_Size_Index);
   EXCEPTION_DECLARATION(Exception_Size_Match,Exception_Size);

Lancement de l’exception

Pour lancer les exceptions ainsi définies, on pourrait coder en dur les informations d’emplacement, mais il est plus élégant d’utiliser les macros du compilateur. Cependant, taper les trois macros dans l’appel de l’exception est fastidieux.

Nous allons donc utiliser une autre macro :
#define EXCEPTION_INFOS __FUNCTION__,__FILE__,__LINE__

Qui permet d’appeller simplement une exception :
throw Exception_Size_Index("Vecteur de taille nul", EXCEPTION_INFOS );

Laquelle pourra, grâce à la hierarchie, être attrappée via sa classe mère, par exemple :

try {
   // du code
} catch( Exception_Size & e ) {
   cerr << "Error: " << e.what() << endl;
}


Post-scriptum
Merci à Caeies pour l’aide. Ce code a été mis en place dans le projet oMetah, voir notamment le fichier Exception_oMetah.hpp

Commentaires

Par nicodemle 16 octobre 2008 : Youpi
Merci pour cet exemple de gestion des exceptions qui économise bcp d’efforts.

Articles populaires

[Accueil] - [Plan du site] - [Rechercher] - [Admin.]       SPIP:Squelette