Dois-je hériter de std::exception?
J'ai vu au moins une source fiable (une classe C++, j'ai pris) de recommander à la demande spécifique de classes d'exceptions en C++ devrait hériter de std::exception
. Je ne suis pas clair sur les avantages de cette approche.
En C# les raisons pour hériter de ApplicationException
sont claires: vous obtenez une poignée de méthodes utiles, les propriétés et les constructeurs et juste à ajouter ou de remplacer ce que vous avez besoin. Avec std::exception
il semble que tout ce que vous obtenez est un what()
méthode pour remplacer la, qui vous pourriez tout aussi bien créer vous-même.
Quels sont donc les avantages, le cas échéant, de l'aide std::exception
comme une classe de base pour mon application spécifique de la classe d'exception? Existe-il des bonnes raisons de ne pas hériter de std::exception
?
- Vous pouvez avoir un coup d'oeil à ceci: stackoverflow.com/questions/1605778/1605852#1605852
- Même si, comme une note de côté sans rapport avec la question en particulier, des classes C++, vous prenez ne doivent pas impérativement être des sources fiables sur les bonnes pratiques vient de sortir de leur propre droit.
Vous devez vous connecter pour publier un commentaire.
Le principal avantage est que le code à l'aide de vos classes n'est pas nécessaire de connaître le type exact de ce que vous
throw
à elle, mais peut simplementcatch
lastd::exception
.Edit: Martin et d'autres ont fait remarquer, vous souhaitez réellement tirer de l'une des sous-classes de
std::exception
déclaré dans<stdexcept>
en-tête.std::exception
est défini dans le<exception>
en-tête (preuve).-1
Le problème avec
std::exception
est qu'il n'y a pas de constructeur (en l'conforme à la norme versions) qui accepte un message.Comme un résultat, je préfère tirer de
std::runtime_error
. C'est dérivé destd::exception
mais ses constructeurs vous permettent de passer d'un C-String ou unstd::string
pour le constructeur qui sera retourné (comme unchar const*
) lorsquewhat()
est appelé.throw error("File not found")
(ce qui est faux) plutôt que dethrow file_not_found_error()
(qui est correcte). Et ne mélangeons pas les gens avec l'exploitation forestière. Oui, vous pouvez vous connecter sur le fait que vous lancer ou attraper une exception, et oui certaines données à l'exception peut de transport n'est pas pour l'utilisateur de voir, mais c'est à côté du sujet.file_not_found_error("File not found")
est correct, parce que si le code de l'attraper comme générique d'exception vous voulez laisser l'utilisateur avec l'humain, de l'amicale popup.std::exception
qui prend unconst char* const
, sans doute à l'aise avec la mise en œuvre de classes de la<stdexcept>
en déchargeant le code partagé de la salle de classe de base, mais le recours à ce que les pauses de la portabilité. Pensé que peut-être pertinente, si ce n'est pas très utile.Raison de l'héritage de
std::exception
est-il "standard" de la classe de base pour les exceptions, il est donc naturel pour les autres personnes sur une équipe, par exemple, de s'attendre à ce que et à la capture de la base destd::exception
.Si vous êtes à la recherche pour plus de commodité, vous pouvez hériter de
std::runtime_error
qui fournitstd::string
constructeur.std::exception
est un excellent idée. Ce que vous ne devriez pas faire est d'hériter de plus que l'un.Une fois, j'ai participé au nettoyage d'une grande base de code où les auteurs précédents avaient jeté des ints, HRESULTS, std::string, char*, au hasard des classes... des choses différentes partout; juste le nom d'un type et il a probablement été jeté quelque part. Et pas de classe de base commune à tous. Croyez-moi, les choses étaient beaucoup plus propre une fois que nous sommes arrivés au point que tous les jetés types avaient une base commune, nous pourrions attraper et ne savent rien allait se passer. Merci donc de faire vous-même (et ceux qui devrez maintenir votre code dans l'avenir) une faveur et de le faire de cette manière dès le début.
Vous devez hériter de boost::exception. Il offre beaucoup plus de fonctionnalités, et bien entendu les façons de transmettre des données supplémentaires... bien sûr, si vous ne l'utilisez pas Boost, puis de les ignorer cette suggestion.
La raison pour laquelle vous pourriez hériter de
std::exception
est parce qu'elle permet de lever une exception qui est pris selon la classe, c'est à dire:Oui, vous devez dériver de
std::exception
.D'autres ont répondu que
std::exception
a le problème que vous ne pouvez pas passer un message texte, mais il n'est généralement pas une bonne idée de tenter de le format d'un message de l'utilisateur au point de le jeter. Au lieu de cela, utiliser l'objet de l'exception pour le transport de toutes les informations pertinentes à la prise de site qui peut ensuite le format de l'utilisateur, le message amical.std::exception
et transporter les informations de l'exception. Mais qui sera responsable de la construction/format du message d'erreur? Le::what()
fonction ou quelque chose d'autre?Il y a un problème avec l'héritage que vous devez savoir à propos de l'objet de la découper. Lorsque vous écrivez
throw e;
un lancer-expression initialise un objet temporaire, appelé l'objet de l'exception, du type de ce qui est déterminé par la suppression de tout haut niveau cv-qualificatifs de la statique type de l'opérande dethrow
. Qui pourrait ne pas être ce que vous attendez. Exemple de problème, vous pouvez trouver ici.Il n'est pas un argument contre l'héritage, c'est juste "doit savoir" info.
throw;
est ok, mais il n'est pas évident que vous devriez écrire quelque chose comme cela.raise()
, en tant que tel:virtual void raise() { throw *this; }
. N'oubliez pas de le remplacer dans chaque dérivé d'exception.Différence: std::runtime_error vs std::exception()
Si vous devrait héritent de celui-ci ou pas, c'est à vous. Standard
std::exception
et son standard descendants proposer une exception possible de la hiérarchie de la structure (division enlogic_error
subhierarchy etruntime_error
subhierarchy) et une exception possible de l'objet de l'interface. Si vous le souhaitez - l'utiliser. Si pour quelque raison vous avez besoin quelque chose de différent - définissez votre propre cadre d'exception.Depuis la langue déjà jette std::exception, vous avez besoin de l'attraper, de toute façon à fournir décent de rapport d'erreur. Vous pouvez aussi bien utiliser la même attraper toutes les exceptions inattendues de votre propre. Aussi, presque toute bibliothèque qui lève des exceptions pourraient tirer de std::exception.
En d'autres termes, de sa soit
ou
Et la deuxième option est certainement mieux.
Si toutes les exceptions possibles à tirer de
std::exception
, votre bloc catch peut simplementcatch(std::exception & e)
et d'être assuré de tout capturer.Une fois que vous avez capturé l'exception, vous pouvez l'utiliser
what
méthode pour obtenir de plus amples renseignements. C++ ne prend pas en charge duck-typing, donc une autre classe avec unwhat
méthode nécessiterait un autre attraper et les différents code pour l'utiliser.Si pour dériver à partir de n'importe quelle type d'exception ou pas, c'est la première question. Cela permet à un seul gestionnaire d'exception pour tous la bibliothèque standard d'exceptions et de votre propre, mais il encourage également ces fourre-tout des gestionnaires. Le problème est que l'on ne devrait intercepter des exceptions on sait comment la gérer. Dans main(), par exemple, la capture de tous les std::exception est probablement une bonne chose si la ce() string sera enregistré comme un dernier recours avant de quitter. Ailleurs, cependant, il est peu probable d'être une bonne idée.
Une fois que vous avez décidé que de dériver à partir d'un standard type d'exception ou pas, la question est de savoir qui devrait être la base. Si votre application n'a pas besoin de l'i18n, vous pourriez penser que la mise en forme d'un message sur le site d'appel est tout aussi bon que l'enregistrement de l'information et de générer le message sur le site d'appel. Le problème est que le message mis en forme peut ne pas être nécessaire. Mieux vaut utiliser un paresseux message schéma de génération, peut-être avec préaffectés de la mémoire. Ensuite, si le message est nécessaire, il sera généré sur l'accès (et, éventuellement, la mise en cache dans l'objet de l'exception). Ainsi, si le message est généré lors de la levée, puis un std::exception dérivées, comme std::runtime_error est nécessaire que la classe de base. Si le message est généré paresseusement, puis std::exception est la base appropriée.
Une autre raison de la sous-classe des exceptions est un meilleur aspect de la conception lorsque vous travaillez sur de grands systèmes encapsulés. Vous pouvez la réutiliser pour des choses telles que la validation des messages, les requêtes utilisateur, fatale erreur de contrôleur et ainsi de suite. Plutôt que de réécrire ou rehooking tous de votre validation comme des messages, vous pouvez simplement "l'attraper" sur le fichier source principal, mais jeter l'erreur de n'importe où dans votre ensemble de classes.
par exemple, Une erreur fatale sera de mettre fin au programme, une erreur de validation seulement clear de la pile et une requête de l'utilisateur va demander à l'utilisateur final une question.
Le faisant de cette manière signifie également que vous pouvez réutiliser les mêmes classes, mais sur les différentes interfaces. par exemple, Une application windows pouvez utiliser la boîte de message, un web service affiche le html et le système de notification journal et ainsi de suite.
Si cette question est assez vieux et a déjà été répondu à beaucoup, je veux juste ajouter une remarque sur la façon de faire la bonne gestion des exceptions en C++11, depuis que je suis en permanence à côté de ce dans les discussions sur les exceptions:
Utilisation
std::nested_exception
etstd::throw_with_nested
Il est décrit sur StackOverflow ici et ici, comment vous pouvez obtenir une trace sur vos exceptions à l'intérieur de votre code sans avoir besoin d'un débogueur ou la lourdeur de la journalisation, en écrivant un bon gestionnaire d'exception qui va renvoyer exceptions imbriquées.
Puisque vous pouvez le faire avec toutes les dérivées de la classe d'exception, vous pouvez ajouter un grand nombre d'informations à une telle trace!
Vous pouvez également prendre un coup d'oeil à mon MWE sur GitHub, où un backtrace ressemblerait à quelque chose comme ceci:
Vous n'avez même pas besoin de sous-classe
std::runtime_error
afin d'obtenir beaucoup d'informations lorsqu'une exception est levée.Le seul avantage que je vois dans la sous-classement (au lieu de simplement en utilisant
std::runtime_error
), c'est que votre gestionnaire d'exception peut attraper vos exception personnalisée et faire quelque chose de spécial. Par exemple: