J'ai vu des problèmes lors de l'utilisation du code C ++ qui, de manière inattendue à l'appelant, jette une exception. Ce n'est pas toujours possible ou pratique de lire toutes les lignes d'un module que vous utilisez pour voir si elle jette des exceptions et, le cas échéant, quel type d'exception. P>
existe-t-il des idiomes établis ou des "meilleures pratiques" qui existent pour traiter ce problème? p>
J'ai pensé à ce qui suit: p>
Dans notre documentation Doxygen, nous pourrions ajouter un commentaire dans chaque fonction qui devrait lancer une exception et son type (s). p>
Nous pourrions avoir une application Utiliser des spécifications d'exception P>
Toute expérience avec ces méthodes, ou toute méthode supplémentaire que je ne suis pas au courant? P> essayer / attrayez (...) code> pour la sécurité. p>
11 Réponses :
Franchement, à peu près n'importe quelle fonction C ++ peut lancer une exception. Vous ne devriez pas trop m'inquiéter de la documentation de cela, mais rendez-vous à la place de votre code de sécurité, en utilisant des idiomes tels que RAII. P>
Bien que je puisse suivre Raii, vous ne pouvez jamais créer de code qui fait preuve d'exception. Il existe toujours des risques de bugs dans des bibliothèques tiers, de l'API OS ou même des modifications des détails du projet qui ne sont pas comptabilisés.
Si vous pouviez éliminer toutes les exceptions ... vous seriez riche ... et bientôt!
J'aime les exceptions! Un million de fois mieux que de vérifier les valeurs de retour!
hein, au plus 23 fois mieux. Les exceptions sont une douleur. Ce n'est pas parce qu'ils sont moins douloureux que les valeurs de retour ne leur font pas une solution bonne i>. : p
Je ne suis pas d'accord, bien sûr que vous devez vous soucier. Vous devriez attraper des exceptions le plus tôt possible. Lorsque des exceptions sont lancées par vous-même, elles font partie de votre interface afin qu'elles soient documentées.
J'utilise les deux 1 et 2. P>
environ 1: Vous ne pouvez pas éviter ou empêcher l'erreur de l'utilisateur. Vous pouvez battre le développeur qui n'a pas écrit correctement le Doxygen à une pulpe, si vous le connaissez. Mais vous ne pouvez pas éviter ou empêcher l'erreur de l'utilisateur, alors laissez tomber la paranoïa. Si l'utilisateur s'est commis, il l'a fait, pas vous. P>
environ 2: C # a construit un moyen d'attraper des exceptions non gérées. Donc, ce n'est pas une «mauvaise chose», même si je suis d'accord, ça sent. Parfois, il est préférable de crash que de courir de manière incohérente, mais j'ai fait une pratique pour enregistrer toutes les exceptions non gérées, puis planter. Cela permet aux gens de m'envoyer le journal afin que je puisse vérifier la trace de la pile et suivre le problème. Ainsi, après chaque correction, de moins et moins de collisions se produisent. P>
Je pense que vous voulez dire C ++, pas c #.
@Neil: Non, je voulais vraiment dire C #, bien que la question soit à propos de C ++. Je n'ai jamais vraiment travaillé avec C ++, mais je suis illustré c # parce que c'est une langue nouvelle qui reflète les concepts les plus récents, afin que cela puisse signifier quelque chose qu'il est acceptable de le faire dans une langue plus récente.
@Leahn Eh bien, il peut vous surprendre que vous sachiez que l'ancienne minuterie C ++ a également un moyen d'attraper des exceptions non gérées :-)
Ou cela peut vous surprendre que c # actuellement reflète beaucoup de concepts vraiment anciens à certains égards. La façon dont vous traitez avec la gestion des exceptions ou le nettoyage des ressources en C # est à peu près ce que les programmeurs C ++ ont fait il y a 15 ans (et ne serait plus Dream i> de faire);)
@Jalf: J'accepte les suggestions. S'ils ne rêvent plus de le faire de cette façon, comment le font-ils? Je veux dire, je trouve que c'est une bonne idée d'attraper toutes les exceptions non fabriquées et de les enregistrer avant de crousser le programme. Essayer de récupérer est une mauvaise idée, mais la journalisation pour le débogage ultérieur n'est pas. Au moins je le pense. Mais vous semblez impliquer que c'est, alors comment faites-vous affaire avec des exceptions non gérées?
Vous devriez toujours attendre des exceptions et les gérer. Malheureusement, il n'y a pas de manière automatisée pour l'ordinateur de faire de la diligence raisonnable pour vous. P>
Réponse courte à la question du titre - L'idiome d'indiquer qu'une fonction peut lancer est pas em> pour le documenter "Cette fonction ne jette pas". C'est-à-dire que tout peut lancer par défaut. P>
C ++ n'est pas Java et ne dispose pas d'exceptions à vérification du compilateur. Il n'y a rien dans C ++ qui permettra au compilateur de vous dire que votre code prétend que cela ne va pas lancer, mais appelle quelque chose qui pourrait. Vous ne pouvez donc pas éviter complètement cela d'être un problème d'exécution. Les outils d'analyse statique peuvent vous aider, pas sûr. P>
Si vous ne vous souciez que de MSVC, vous pouvez envisager d'utiliser une spécification d'exception vide ou Option 2, la capture d'essai de l'application n'est pas vraiment "pour la sécurité", c'est juste parce que vous pensez pouvoir faire quelque chose de plus utile à l'exception (comme imprimer quelque chose de côté et de sortie proprement) que de simplement laisser le C ++ Appel d'exécution Je ferais normalement une variante de (1): pour chaque document de fonction Quelle exception garantit des offres d'exception - Nothow, forte, faible ou aucune. Le dernier est un bug. Le premier est prisé mais rare et avec un bon codage n'est que strictement nécessaire pour les fonctions d'échange et les destructeurs. Oui, il est soumis à une erreur utilisateur, mais tout moyen de codage C ++ avec des exceptions est soumis à une erreur utilisateur. Ensuite, en plus de cela, faites également (2) et / ou (3) si cela vous aide à appliquer (1). P>
Symbian a un dialecte pré-standard de C ++, avec un mécanisme appelé "congé" qui ressemble à des exceptions à certains égards. La convention de Symbian est que toute fonction qui pourrait partir doit être nommée avec un L à la fin: __ DeclSpec (Nothrow) code> sur les fonctions qui ne jettent pas, et
lancer (...) code> sur les fonctions qui font. Cela n'entraînera pas de code inefficace, car MSVC n'émettra pas le code pour vérifier que les fonctions déclarées, rien ne jettent. GCC peut faire la même chose avec
-fno-imposerce-eh-specs code>, vérifier votre documentation de compilateur. Tout sera alors automatiquement documenté. p>
Terminez code>. Si vous écrivez le code sur l'hypothèse que quelque chose ne jettera pas, et ce n'est en réalité que vous pourriez avoir devenu indéfini avant que l'un d'entre eux se produise, par exemple si un destructeur fait une fausse hypothèse d'un état cohérent. p>
CreateEL code>,
ConnectL code>, etc. En moyenne, cela réduit l'erreur utilisateur, car peut voir plus facilement si vous appelez quelque chose qui pourrait partir. Comme on pouvait s'y attendre, les mêmes personnes détestent cela qui détestent les applications de la notation hongroise et, si presque toutes les fonctions laissent cela cesse d'être utile. Et comme vous pouvez vous attendre, si vous écrivez une fonction qui laisse sans l dans le nom, cela peut être bon pendant le débogueur avant de comprendre le problème, car vos hypothèses vous éloignent du bug actuel. p>
C ++, antérieur à C ++ 11, défini une spécification de lancement. Voir Cette question . Cela a été mon expérience dans le passé que les compilateurs Microsoft ignorent la spécification C ++. La notion totale des "exceptions vérifiées" est controversée, en particulier dans le royaume Java. De nombreux développeurs considèrent comme une expérience échouée. p>
True +1, seuls les définissent i> dans la première phrase semblent impliquer que cet élément linguistique est toujours "efficace" pour C ++. Je suggère de mettre à jour cette réponse, il est précieux (au moins) pour des raisons historiques.
Utilisez DOCUMATION DOXYGEN pour décrire vos méthodes. Lorsque vous les utilisez, vous devrez vérifier cette documentation pour voir quels paramètres sont leurs paramètres et quelles exceptions elles lancent. P>
Ecrire des tests d'unité Pour exercer votre code dans les cas d'exception sont lancés. p>
La documentation semble être la seule méthode raisonnable que je connaisse. P>
En ce qui concerne les spécifications d'exception, voici un ancien article (2002) de Herb Sutter sur le sujet http: // www.ddj.com/cpp/184401544 Il aborde pourquoi cette fonctionnalité de la langue ne nous donne pas la sécurité de la compilation et finit par la conclusion: P>
Voici donc ce qui semble être le meilleur Conseils que nous en tant que communauté ont appris à compter d'aujourd'hui: p>
morale n ° 1: ne jamais écrire une exception Spécification. P>
morale n ° 2: sauf éventuellement un vide un, mais si j'étais vous, j'éviterais même cela. p> blockQuote>
non.
La seule chose commune est d'indiquer que vous ne jetez rien.
Et puis vous devez également vous assurer manuellement qu'aucune exception ne peut réellement échapper à votre méthode / fonction. Remarque: Si des exceptions échappent à la méthode, l'application sera terminée.
#include <stdexcept> class MyException: public std::exception { public: ~MyException() throw() {} char* what() const throw() { try { // Do Stuff that may throw return "HI"; } // Exceptions must not escape this method // So catch everything. catch(...) { return "Bad Stuff HAppening Cant Make Exception Message."; } } };
Le moyen idiomatique de résoudre le problème est de ne pas indiquer que votre code peut lancer des exceptions, mais pour mettre en œuvre une sécurité d'exception dans vos objets. La norme définit plusieurs garanties d'exception Les objets doivent mettre en œuvre: P>
Et bien sûr, la norme documente le niveau de sécurité d'exception pour chaque classe de bibliothèque standard. P>
C'est vraiment la voie à traiter avec des exceptions en C ++. Plutôt que de marquer quel code peut ou ne peut pas lancer d'exceptions, utilisez RAII pour que vos objets soient nettoyés et mettre une pensée dans la mise en œuvre du niveau de sécurité d'exception approprié dans vos objets Raii, afin qu'ils puissent survivre sans manipulation spéciale si une exception est lancée. P>
Exceptions ne causent vraiment que des problèmes s'ils permettent à vos objets d'être laissés dans un état invalide em>. Cela ne devrait jamais arriver. Vos objets devraient toujours em> mettre en œuvre au moins la garantie de base. (et la mise en œuvre d'une classe de conteneurs qui fournit le niveau approprié de la sécurité des exceptions est un exercice C ++ C ++;)) P>
Quant à la documentation, lorsque vous êtes capable em> pour déterminer pour certaines exceptions qu'une fonction peut lancer, par tous les moyens n'hésitez pas à le documenter. Mais en général, lorsque rien d'autre n'est spécifié, il est supposé qu'une fonction peut lancer. La spécification de lancer vide est parfois utilisée pour documenter lorsqu'une fonction jamais em> jette. Si ce n'est pas là, supposez que la fonction peut lancer. P>
"Les exceptions ne causent vraiment que des problèmes s'ils permettent à vos objets d'être laissés dans un état invalide." > Non, ils sont également un problème lorsque l'appelant ne sait pas quelle méthode jette et ne gère pas toutes les exceptions correctement.
Dépend du genre de problème dont nous parlons. Je parle du problème le plus fondamental: votre programme est laissé dans un état invalide ou indéterminé. Cela n'arrivera pas si vos objets sont individuellement sûrs. Et cela signifie que vous pouvez simplement gérer l'exception que cela a du sens, sans avoir à vous soucier de l'exactitude.
Il existe un moyen de spécifier quelles exceptions une fonction peut lancer en C ++. Un exemple extrait du livre STROSTRUP est
void f(int a) throw (x2, x3);
Non, tu ne peux pas. La syntaxe vous permet de Document i> Ce que vous pense i> Il va lancer, mais cela n'est pas appliqué par le compilateur. Voir Stackoverflow.com / Questions / 88573 / ... Je pense que cela est effectivement pire que de ne pas avoir de telles décoration. Maintenant, les lecteurs du code penseront que c'est une garantie, quand elle n'est essentiellement qu'un commentaire. :(
document Quoi de niveau de Sécurité des exceptions une> une fonction garantie. Comme Steve Jessop pointait sa réponse, il y a nombre de niveaux. Idéalement, s'ils sont documentés pour les interfaces toutes, ou au moins nécessaires au minimum: a) ne jette jamais em> ou b) peut jeter p> p> p>
Lire à propos de Abrahams Garanties de sécurité d'exception expliqué par Herb Sutter . P>
li>
Je doute fortement qu'il serait pratique dans une grande base de code. En ce qui concerne et Il est difficile de comprendre quoi faire les préoccupations em>, une bonne règle est de ne pas attraper que dans des endroits où vous voulez faire face à une exception, sinon laissez-le Bubble Up. Ce n'est pas une bonne idée d'attraper et d'éteindre des exceptions dès qu'ils apparaissent, juste parce que ... ce sont des exceptions, vous sentez donc que vous devez faire quelque chose avec cela. Dans des systèmes complexes, il est bon d'avoir un mécanisme de journalisation, il est donc plus facile de tracer un problème. P>
li>
ne le fais pas. Lisez Herb Sutter's Un regard pragmatique sur les spécifications d'exception et des articles connexes. P>
li>
ol>