Différence: std :: runtime_error vs std :: exception ()

128

Quelle est la différence entre std::runtime_erroret std::exception? Quelle est l'utilisation appropriée de chacun? Pourquoi sont-ils différents en premier lieu?

sivabudh
la source

Réponses:

153

std::exceptionest la classe dont le seul but est de servir de classe de base dans la hiérarchie des exceptions. Il n'a pas d'autres utilisations. En d'autres termes, conceptuellement, il s'agit d'une classe abstraite (même si elle n'est pas définie comme une classe abstraite au sens C ++ du terme).

std::runtime_errorest une classe plus spécialisée, descendant de std::exception, destinée à être lancée en cas de diverses erreurs d' exécution . Il a un double objectif. Il peut être lancé par lui-même, ou il peut servir de classe de base à divers types encore plus spécialisés d'exceptions d'erreur d'exécution, tels que std::range_error, std::overflow_erroretc. Vous pouvez définir vos propres classes d'exceptions descendant de std::runtime_error, ainsi que vous pouvez définir votre propre exception classes descendant de std::exception.

Tout comme std::runtime_error, la bibliothèque standard contient std::logic_error, également descendant de std::exception.

L'intérêt d'avoir cette hiérarchie est de donner à l'utilisateur la possibilité d'utiliser toute la puissance du mécanisme de gestion des exceptions C ++. Puisque la clause 'catch' peut intercepter des exceptions polymorphes, l'utilisateur peut écrire des clauses 'catch' qui peuvent intercepter des types d'exceptions à partir d'un sous-arbre spécifique de la hiérarchie d'exceptions. Par exemple, catch (std::runtime_error& e)capturera toutes les exceptions du std::runtime_errorsous-arbre, laissant toutes les autres passer (et remonter plus haut dans la pile d'appels).

PS La conception d'une hiérarchie de classes d'exceptions utile (qui vous permettrait de capturer uniquement les types d'exceptions qui vous intéressent à chaque point de votre code) est une tâche non triviale. Ce que vous voyez dans la bibliothèque C ++ standard est une approche possible, proposée par les auteurs du langage. Comme vous le voyez, ils ont décidé de diviser tous les types d'exceptions en «erreurs d'exécution» et «erreurs logiques» et vous ont laissé procéder à partir de là avec vos propres types d'exceptions. Il existe, bien sûr, d'autres moyens de structurer cette hiérarchie, qui pourraient être plus appropriés dans votre conception.

Mise à jour: portabilité Linux vs Windows

Comme Loki Astari et unixman83 l'ont noté dans leur réponse et leurs commentaires ci-dessous, le constructeur de la exceptionclasse ne prend aucun argument selon le standard C ++. Microsoft C ++ a un constructeur prenant des arguments dans la exceptionclasse, mais ce n'est pas standard. La runtime_errorclasse a un constructeur prenant des arguments ( char*) sur les deux plates-formes, Windows et Linux. Pour être portable, une meilleure utilisation runtime_error.

(Et rappelez-vous, ce n'est pas parce qu'une spécification de votre projet indique que votre code ne doit pas s'exécuter sous Linux, cela ne signifie pas qu'il ne doit jamais s'exécuter sous Linux.)

Fourmi
la source
1
Merci. très bonne réponse. bien que je me demande s'il est jamais nécessaire d'avoir un type différent d'exception ... juste une pensée cependant.
sivabudh
1
S'il existe une possibilité à partir de laquelle l'exception peut être recouverte, alors un autre type d'exception peut être utile car nous pouvons utiliser le mécanisme de gestion des exceptions pour diriger l'exception vers le gestionnaire qui tentera de corriger le problème. S'il n'y a aucune chance de récupération, l'une des exceptions standard convient.
Martin York
1
En passant, il n'y a aucune règle, nulle part, qui vous oblige à dériver std::exception. Bien sûr, toutes stdchoses en jettent des classes dérivées, mais il n'y a absolument aucune raison de ne lancer que des std::exceptionobjets dérivés.
rubenvb
1
@rubenvb Je ne savais pas à ce sujet, mais je pense que cela clarifiera le code pour une maintenance future si seuls les objets des classes dérivées de l'exception sont lancés. Exemple: j'aime savoir quelles exceptions personnalisées sont implémentées dans ma base de code et rechercher des classes dérivées d'exceptions.
this.myself
21

std::exceptiondevrait être considéré (notez le considéré) la base abstraite de la hiérarchie d'exceptions standard. En effet, il n'y a pas de mécanisme pour passer un message spécifique (pour ce faire, vous devez dériver et spécialiser what()). Il n'y a rien qui vous empêche d'utiliser std :: exception et pour les applications simples, cela peut être tout ce dont vous avez besoin.

std::runtime_errord'autre part, a des constructeurs valides qui acceptent une chaîne comme message. Quand what()est appelé, un pointeur de char const est retourné qui pointe sur une chaîne C qui a la même chaîne que celle qui a été passée au constructeur.

try
{
    if (badThingHappened)
    {
         throw std::runtime_error("Something Bad happened here");
    }
}
catch(std::exception const& e)
{
    std::cout << "Exception: " << e.what() << "\n";
} 
Martin York
la source
1
Merci pour la réponse Martin. Cependant, j'utilise std :: exception () de la même manière que vous avez décrit ci-dessus. ie le constructeur std :: exception () peut aussi prendre un std :: string () ou const char *.
sivabudh
14
Pas selon la norme. std :: exception a un constructeur qui ne prend aucun argument. L'utilisation d'une version qui accepte une std :: string ou une C-String n'est pas portable.
Martin York
10
Grâce à Microsoft, je me suis habitué à lancer std::exception(std::string). Maintenant, je me rends compte que je dois lancer std::runtime_errorsi je veux que mon code fonctionne sous Linux (GCC).
unixman83