D'une manière standard en C++ pour définir une classe d'exception et de lancer des exceptions
Je veux construire une classe de fonctions qui peuvent lever des exceptions que j'ai envie de l'attraper quand je l'utilise.
J'hérite de my_exception standard de la classe exception.
- Je mettre en œuvre la ce() la fonction de sorte qu'elle retourne une chaîne de caractères qui est stocké dans une chaîne privée variable
Je pense qu'il serait préférable de définir l'exception, comme une classe imbriquée, la façon dont c'est fait dans la bibliothèque iostream avec ios_base::l'échec.
Ce que je suis moins sûr, est de savoir où et comment je dois définir l'objet de la my_excpetion. Je souhaite que je pourrais voir l'intérieur du code de la iostream fonctions et de voir comment ils ont fait.
J'ai pensé à plusieurs options:
- Pour chaque motif d'exception, je peux définir une instance statique de my_exception, avec un constructeur qui reçoit une chaîne de caractères et l'enregistrer sur ma chaîne privée pointeur.
- Pour chaque motif d'exception, je peux définir une autre classe qui hérite de my_exception et de mettre en œuvre ce qui, comme une fonction qui renvoie une chaîne constante (la raison).
Je peux tenir une instance de chacun des exceptions dans des sous-classes, ou de jeter le type.
BTW, quand nous avons l'habitude de jeter type et pas l'instance? - Je suppose que c'est faux: chaque fois que je veux lancer une exception, pour créer une nouvelle my_exception avec un constructeur qui reçoit une chaîne de caractères. Ceci est fait en Java, mais ce que je comprends, il va être problématique en C++ parce que l'exception doit être supprimé quelque part. Droit?
Je pense que le 1er est celui de droite, est-il?
Il n'y a plus des options standard?
Merci beaucoup!
OriginalL'auteur ip84 | 2011-05-28
Vous devez vous connecter pour publier un commentaire.
Réponse courte: Vous allez vouloir jeter les exceptions comme des objets plutôt que comme des pointeurs. Vous pourrez prendre comme référence.
Plus réponse: toutes les options de la liste sont valides. En général, la raison pour laquelle vous allez vouloir jeter un objet, plutôt qu'un pointeur est dommage parce que les choix que vous donner vous-même et vos clients lorsque l'exception est interceptée.
Si vous l'attrapez par pointeur,
catch (my_exception* e)
vous ne savez pas de regarder si vous devez le supprimer de la mémoire ou pas.Si vous l'attrapez par la valeur,
catch (my_exception e)
ensuite, vous avez un risque de trancher, si l'objet de l'exception finit par être une classe de base avec quelques autres classes dérivées.Attraper par référence a aucun de ces problèmes. Si vous écrivez
catch (my_exception& r)
ensuite, vous pouvez attraper des objets polymorphes, et vous n'avez pas à vous soucier de libération de la mémoire.Donc, pour répondre à votre autre question, lorsque vous lancer, il suffit de jeter un objet temporaire:
throw my_exception()
. Cela crée un objet temporaire est (probablement) copiés lors de la levée, pris par référence, et détruit automatiquement quand elle est hors de portée, à la fin de votre bloc catch. (C'est en fait un autre avantage de la capture par référence au cours de catch-par-valeur, depuis l'attraper par valeur, crée encore un autre exemplaire quand il est pris.)Que pour d'autres, issus des classes d'exception, c'est un choix de style. Découlant de my_exception avec un autre (quoi) la mise en œuvre est assez standard. Je ne dirais pas que vous avez besoin pour obtenir la fantaisie avec le stockage des chaînes ou des instances dans les objets statiques - ils sont petits, et la construction de l'un va prendre pratiquement pas de temps par rapport au processus de déroulement de la pile lorsque l'exception est levée.
notez que, sauf si vous prévoyez sur la modification de l'exception (l'ajout de contexte et de renvoi), alors vous devez l'attraper par
const
de référence.Bon point. Je vais préciser que. N'est-ce pas le cas bien que, en l'absence d'optimisation du compilateur, l'original temporaire que vous créez est copié et détruit, et que c'est cette copie qui est réellement pris en référence?
M. C'est intéressant, je n'ai pas entendu cette recommandation avant. Quel est l'avantage de faire de cette façon? Lorsque vous déclarez une fonction comme paramètre const &, vous gagnez l'avantage d'être capable de se lier à des valeurs r, et vous assurer de l'appelant que vous ne serez pas modifier l'objet qui est passée, mais que ces avantages ne s'appliquent pas dans un bloc catch. Un (certes purement théorique) inconvénient serait une impossibilité d'appeler n'importe quel non-const membres sur certains arbitraire de l'objet renvoyé.
En fait, ne pas être en mesure de modifier l'objet ne s'applique pas 🙂 Il indique au lecteur que vous ne va pas changer l'exception de la raison, ni ajouter de tout contexte. Je dois avouer que je suis récemment rendu compte de cette possibilité, moi-même, donc mon code de base est l'inadéquation de l'
ex&
etex const&
blocs catch, mais je trouve ce dernier une meilleure pratique. Je suis un peuconst
-addict 😉OriginalL'auteur jwismar
Si vous dérivez de std::runtime_error vous n'avez pas besoin de définir votre propre membre pour stocker la chaîne. Ceci est fait pour vous dans le std::exception (la base de std::runtime_error). Il n'est pas défini comment l'exception des magasins de la chaîne, mais il devrait toujours fonctionner.
std::exception
n'a pas de constructeur de chaînes ou de stockage, maisstd::runtime_error
. (MSVC la soutient dansstd::exception
de toute façon, si.)Tout à fait exact. C'est pourquoi j'utilise std::runtime_error
Ok, j'étais juste confus au sujet de cette partie: "vous n'avez pas besoin de définir votre propre membre pour stocker la chaîne. Ceci est fait pour vous dans le std::exception"; ce n'est pas (nécessairement) vrai.
Techniquement vrai. Ses pas définie par la norme, si le message est stocké pour l'un quelconque des types dérivés de std::exception et donc chaque type peut utiliser sa propre méthode pour stocker le message physique. Tout ce que nous savons pour sûr sur les std::runtime_error:
Postcondition (of the constructor with a single std::string argument what_arg: strcmp(what(), what_arg.c_str()) == 0.
OriginalL'auteur Martin York
Rien de mal avec l'un de vos options. Le numéro 3 est OK, tant que vous faites une variable locale et de ne pas utiliser
new
, car il n'y a pas besoin de supprimer l'exception de l'objet, il sera détruit dès que vous jetez. Vous aurez besoin de faire un constructeur de copie et de copie de l'opérateur, en raison de la levée d'une exception sera effectivement une copie de celle que vous donnez à lathrow
déclaration.L'Option 1 serait inhabituel parce qu'il n'est pas normalement nécessaire.
Pour l'option 2, vous devez créer une instance de la classe à jeter. Il n'est pas possible de jeter un type, seulement une instance d'un type.
OriginalL'auteur Mark Ransom