Il est possible de spécifier les exceptions qui peuvent être lancées par une fonction. Pour cela, il faut faire suivre son en-tête du mot clé throw avec, entre parenthèses et séparées par des virgules, les classes des exceptions qu'elle est autorisée à lancer. Par exemple, la fonction suivante :
int fonction_sensible(void)
throw (int, double, erreur)
 ...
n'a le droit de lancer que des exceptions du type int, double ou erreur. Si une exception d'un autre type est lancée, par exemple une exception du type char *, il se produit encore une fois une erreur à l'exécution.
En fait, la fonction std::unexpected est appelée. Cette fonction se comporte de manière similaire à std::terminate, puisqu'elle appelle par défaut une fonction de traitement de l'erreur qui elle-même appelle la fonction std::terminate (et donc abort en fin de compte). Cela conduit à la terminaison du programme. On peut encore une fois changer ce comportement par défaut en remplaçant la fonction appelée par std::unexpected par une autre fonction à l'aide de std::set_unexpected, qui est déclarée dans le fichier d'en-tête exception. Cette dernière attend en paramètre un pointeur sur la fonction de traitement d'erreur, qui ne doit prendre aucun paramètre et qui ne doit rien renvoyer. std::set_unexpected renvoie le pointeur sur la fonction de traitement d'erreur précédemment appelée par std::unexpected.
Il est possible de relancer une autre exception à l'intérieur de la fonction de traitement d'erreur. Si cette exception satisfait la liste des exceptions autorisées, le programme reprend son cours normalement dans le gestionnaire correspondant. C'est généralement ce que l'on cherche à faire. Le gestionnaire peut également lancer une exception de type std::bad_exception, déclarée comme suit dans le fichier d'en-tête exception :
class bad_exception : public exception
public:
 bad_exception(void) throw();
 bad_exception(const bad_exception &) throw();
 bad_exception &operator=(const bad_exception &) throw();
 virtual ~bad_exception(void) throw();
 virtual const char *what(void) const throw();
Cela a pour conséquence de terminer le programme.
Enfin, le gestionnaire d'exceptions non autorisées peut directement mettre fin à l'exécution du programme en appelant std::terminate. C'est le comportement utilisé par la fonction std::unexpected définie par défaut.
Exemple 9-3. Gestion de la liste des exceptions autorisées.
using namespace std;
void mon_gestionnaire(void)
 cout « "Une exception illégale a été lancée." « endl;
 cout « "Je relance une exception de type int." « endl;
 throw 2;
int f(void) throw (int)
 throw "5.35";
int main(void)
 set_unexpected(&mon_gestionnaire);
 try
 f();
 catch (int i)
 cout « "Exception de type int reçue : " «
 i « endl;
 return 0;
la liste des exceptions autorisées dans une fonction ne fait pas partie de sa signature. Elle n'intervient donc pas dans les mécanismes de surcharge des fonctions. De plus, elle doit se placer après le mot clé const dans les déclarations de fonctions membres const (en revanche, elle doit se placer avant =0 dans les déclarations des fonctions virtuelles pures).
On prendra garde au fait que les exceptions ne sont pas générées par le mécanisme de gestion des erreurs du C++ (ni du C). Cela signifie que pour avoir une exception, il faut la lancer, le compilateur ne fera pas les tests pour vous (tests de débordements numériques dans les calculs par exemple). Cela supposerait de prédéfinir un ensemble de classes pour les erreurs génériques. Les tests de validité d'une opération doivent donc être faits malgré tout et, le cas échéant, il faut lancer une exception pour reporter le traitement en cas d'échec. De même, les exceptions générées par la machine hôte du programme ne sont en général pas récupérées par les implémentations et, si elles le sont, les programmes qui les utilisent ne sont pas portables.

Programmation C-C++/Les exceptions/Hiérarchie des exceptions

Le mécanisme des exceptions du C++ se base sur le typage des objets, puisque le lancement d'une exception nécessite la construction d'un objet qui la caractérise, et le bloc catch destination de cette exception sera sélectionné en fonction du type de cet objet. Bien entendu, les objets utilisés pour lancer les exceptions peuvent contenir des informations concernant la nature des erreurs qui se produisent, mais il est également possible de classifier ces erreurs par catégories en se basant sur leurs types.
En effet, les objets exceptions peuvent être des instances de classes disposant de relations d'héritage. Comme les objets des classes dérivées peuvent être considérés comme des instances de leurs classes de base, les gestionnaires d'exception peuvent récupérer les exceptions de ces classes dérivées en récupérant un objet du type d'une de leurs classes de base. Ainsi, il est possible de classifier les différents cas d'erreurs en définissant une hiérarchie de classe d'exceptions, et d'écrire des traitements génériques en n'utilisant que les objets d'un certain niveau dans cette hiérarchie.
Le mécanisme des exceptions se montre donc plus puissant que toutes les autres méthodes de traitement d'erreurs à ce niveau, puisque la sélection du gestionnaire d'erreur est automatiquement réalisée par le langage. Cela peut être très pratique pour peu que l'on ait défini correctement sa hiérarchie de classes d'exceptions.
Exemple 9-4. Classification des exceptions.
using namespace std;
// Classe de base de toutes les exceptions :
class ExRuntimeError
};
// Classe de base des exceptions pouvant se produire
// lors de manipulations de fichiers :
class ExFileError : public ExRuntimeError
};
// Classes des erreurs de manipulation des fichiers :
class ExInvalidName : public ExFileError
};
class ExEndOfFile : public ExFileError
};
class ExNoSpace : public ExFileError
};
class ExMediumFull : public ExNoSpace
};
class ExFileSizeMaxLimit : public ExNoSpace
};
// Fonction faisant un travail quelconque sur un fichier :
void WriteData(const char *szFileName)
 // Exemple d'erreur :
 if (szFileName == NULL) throw ExInvalidName();
 else
 // Traitement de la fonction
 // etc.
 // Lancement d'une exception :
 throw ExMediumFull();
void Save(const char *szFileName)
 try
 WriteData(szFileName);
 // Traitement d'un erreur spécifique :
 catch (ExInvalidName &)
 cout « "Impossible de faire la sauvegarde" « endl;
 // Traitement de toutes les autres erreurs en groupe :
 catch (ExFileError &)
 cout « "Erreur d'entrée / sortie" « endl;
int main(void)
 Save(NULL);
 Save("data.dat");
 return 0;
La bibliothèque standard C++ définit elle-même un certain nombre d'exceptions standards, qui sont utilisées pour signaler les erreurs qui se produisent à l'exécution des programmes. Quelques-unes de ces exceptions ont déjà été présentées avec les fonctionnalités qui sont susceptibles de les lancer. Vous trouverez une liste complète des exceptions de la bibliothèque standard du C++ dans la Section 13.2.

Programmation C-C++/Les exceptions/Exceptions dans les constructeurs