En C ++, vous pouvez spécifier qu'une fonction peut ou non lever une exception à l'aide d'un spécificateur d'exception. Par exemple:
void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type
Je doute de les utiliser réellement pour les raisons suivantes:
- Le compilateur n'applique pas vraiment les spécificateurs d'exception de manière rigoureuse, donc les avantages ne sont pas grands. Idéalement, vous aimeriez obtenir une erreur de compilation.
- Si une fonction viole un spécificateur d'exception, je pense que le comportement standard est de terminer le programme.
- Dans VS.Net, il traite le jet (X) comme un jet (...), donc l'adhésion à la norme n'est pas forte.
Pensez-vous que les spécificateurs d'exception devraient être utilisés?
Veuillez répondre par «oui» ou «non» et fournir quelques raisons pour justifier votre réponse.
Réponses:
Non.
Voici plusieurs exemples de raisons:
Le code du modèle est impossible à écrire avec des spécifications d'exception,
Les copies peuvent lancer, le passage de paramètre peut déclencher et
x()
peut lever une exception inconnue.Les spécifications d'exception ont tendance à interdire l'extensibilité.
pourrait évoluer vers
Vous pourriez vraiment écrire cela comme
Le premier n'est pas extensible, le second est trop ambitieux et le troisième est vraiment ce que vous entendez quand vous écrivez des fonctions virtuelles.
Code hérité
Lorsque vous écrivez du code qui repose sur une autre bibliothèque, vous ne savez pas vraiment ce qu'il pourrait faire quand quelque chose va terriblement mal.
g
se terminera, lorsquelib_f()
jette. Ce n'est (dans la plupart des cas) pas ce que vous voulez vraiment.std::terminate()
ne devrait jamais être appelé. Il est toujours préférable de laisser l'application planter avec une exception non gérée, à partir de laquelle vous pouvez récupérer une trace de pile, que de mourir silencieusement / violemment.Écrivez du code qui renvoie les erreurs courantes et les lance dans des occasions exceptionnelles.
Néanmoins, lorsque votre bibliothèque lève simplement vos propres exceptions, vous pouvez utiliser des spécifications d'exception pour indiquer votre intention.
la source
try {...} catch (<specified exceptions>) { <do whatever> } catch (...) { unexpected(); ]
construction, que vous vouliez ou non un bloc try.try { <<...code...>> } catch(...) /* stack guaranteed to be unwound here and dtors run */ { throw; /* pass it on to the runtime */ }
terminate()
? Pourquoi ne pas simplement appelerabort()
?Évitez les spécifications d'exception en C ++. Les raisons que vous donnez dans votre question sont un bon début pour savoir pourquoi.
Voir "Un regard pragmatique sur les spécifications d'exception" de Herb Sutter .
la source
throw(optional-type-id-list)
) est obsolète en C ++ 11. Ils sont toujours dans la norme, mais je suppose qu'un coup de semonce a été envoyé pour que leur utilisation soit examinée attentivement. C ++ 11 ajoute lanoexcept
spécification et l'opérateur. Je ne connais pas assez de détails pournoexcept
en parler . Cet article semble assez détaillé: akrzemi1.wordpress.com/2011/06/10/using-noexcept Et Dietmar Kühl a un article dans le Overload Journal de juin 2011: accu.org/var/uploads/journals/overload103.pdfthrow(something)
est considéré comme inutile et une mauvaise idée.throw()
est utile.Je pense que les
spécificateurs d'exception standard sauf convention (pour C ++) étaient une expérience de la norme C ++ qui a échoué pour la plupart.
L'exception étant que le spécificateur no throw est utile, mais vous devez également ajouter le bloc try catch approprié en interne pour vous assurer que le code correspond au spécificateur. Herb Sutter a une page sur le sujet. Gotch 82
De plus, je pense qu'il vaut la peine de décrire les garanties d'exception.
Il s'agit essentiellement de la documentation sur la manière dont l'état d'un objet est affecté par les exceptions échappant à une méthode sur cet objet. Malheureusement, ils ne sont pas appliqués ou mentionnés par le compilateur.
Boost et exceptions
Garanties d'exception
Aucune garantie:
Garantie de base:
Garantie forte: (aka garantie transactionnelle)
Aucune garantie de jet:
la source
Guarantee that functions will only throw listed exceptions (possibly none)
. Pas vrai. Cela garantit seulement que si la fonction lève ces exceptions, l'application se terminera.Enable compiler optimizations based on the knowledge that only listed exceptions (possibly none) will be thrown
Je ne peux pas faire ça. Parce que je viens de souligner que vous ne pouvez pas garantir que l'exception ne sera pas levée.throw()
(ne lance pas). " Cela garantit seulement que si la fonction lève ces exceptions, l'application se terminera " Non "pas vrai" signifie vrai. Il n'y a aucune garantie en C ++ qu'une fonction n'appelleterminate()
jamais. " Parce que je viens de signaler que vous ne pouvez pas garantir que l'exception ne sera pas levée " Vous garantissez que la fonction ne sera pas lancée. C'est exactement ce dont vous avez besoin.gcc émettra des avertissements lorsque vous enfreignez les spécifications d'exception. Ce que je fais est d'utiliser des macros pour utiliser les spécifications d'exception uniquement en mode "lint" compilez expressément pour vérifier que les exceptions sont conformes à ma documentation.
la source
Le seul spécificateur d'exception utile est "throw ()", comme dans "don't throw".
la source
Les spécifications d'exception ne sont pas des outils très utiles en C ++. Cependant, il / y a / une bonne utilisation pour eux, s'ils sont combinés avec std ::xpected.
Ce que je fais dans certains projets, c'est du code avec des spécifications d'exception, puis j'appelle set_unexpected () avec une fonction qui lèvera une exception spéciale de ma propre conception. Cette exception, lors de la construction, obtient une trace (d'une manière spécifique à la plate-forme) et est dérivée de std :: bad_exception (pour lui permettre d'être propagée si vous le souhaitez). Si cela provoque un appel terminate (), comme il le fait habituellement, la trace arrière est imprimée par what () (ainsi que l'exception d'origine qui l'a causé; pas difficile à trouver) et donc j'obtiens des informations sur l'emplacement de mon contrat. violé, par exemple quelle exception de bibliothèque inattendue a été levée.
Si je fais cela, je n'autorise jamais la propagation des exceptions de bibliothèque (sauf celles std) et je dérive toutes mes exceptions de std :: exception. Si une bibliothèque décide de lancer, je vais attraper et convertir dans ma propre hiérarchie, ce qui me permet de toujours contrôler le code. Les fonctions modèles qui appellent des fonctions dépendantes devraient éviter les spécifications d'exception pour des raisons évidentes; mais il est rare d'avoir une interface de fonction basée sur des modèles avec du code de bibliothèque de toute façon (et peu de bibliothèques utilisent vraiment des modèles de manière utile).
la source
Si vous écrivez du code qui sera utilisé par des personnes qui préfèrent regarder la déclaration de fonction plutôt que tout commentaire autour d'elle, alors une spécification leur dira quelles exceptions ils pourraient vouloir intercepter.
Sinon, je ne trouve pas particulièrement utile d'utiliser autre chose que
throw()
d'indiquer que cela ne lève aucune exception.la source
Non. Si vous les utilisez et qu'une exception est levée que vous n'avez pas spécifiée, que ce soit par votre code ou par le code appelé par votre code, le comportement par défaut est de mettre fin rapidement à votre programme.
De plus, je pense que leur utilisation a été déconseillée dans les versions actuelles de la norme C ++ 0x.
la source
Une spécification "throw ()" permet au compilateur d'effectuer des optimisations lors de l'analyse de flux de code s'il sait que la fonction ne lèvera jamais d'exception (ou du moins promet de ne jamais lever d'exception). Larry Osterman en parle brièvement ici:
http://blogs.msdn.com/larryosterman/archive/2006/03/22/558390.aspx
la source
En général, je n'utiliserais pas de spécificateurs d'exception. Cependant, dans les cas où une autre exception venait de la fonction en question que le programme serait définitivement incapable de corriger , alors cela peut être utile. Dans tous les cas, assurez-vous de documenter clairement les exceptions qui peuvent être attendues de cette fonction.
Oui, le comportement attendu d'une exception non spécifiée lancée à partir d'une fonction avec des spécificateurs d'exception est d'appeler terminate ().
Je noterai également que Scott Meyers aborde ce sujet dans un C ++ plus efficace. Son C ++ efficace et son C ++ plus efficace sont des livres fortement recommandés.
la source
Oui, si vous aimez la documentation interne. Ou peut-être écrire une bibliothèque que d'autres utiliseront, afin qu'ils puissent dire ce qui se passe sans consulter la documentation. Lancer ou ne pas lancer peut être considéré comme faisant partie de l'API, presque comme la valeur de retour.
Je suis d'accord, ils ne sont pas vraiment utiles pour appliquer l'exactitude du style Java dans le compilateur, mais c'est mieux que rien ou des commentaires aléatoires.
la source
Ils peuvent être utiles pour les tests unitaires afin que, lors de l'écriture des tests, vous sachiez à quoi s'attendre de la fonction à lancer en cas d'échec, mais il n'y a aucune application qui les entoure dans le compilateur. Je pense que ce sont du code supplémentaire qui n'est pas nécessaire en C ++. Quel que soit votre choix, tout ce dont vous devez être sûr, c'est que vous suivez la même norme de codage dans tout le projet et les membres de l'équipe afin que votre code reste lisible.
la source
Extrait de l'article:
http://www.boost.org/community/exception_safety.html
Et en effet, je peux penser à des moyens de sécuriser les exceptions des classes de modèles. À moins que vous n'ayez pas le contrôle sur toutes les sous-classes, vous pouvez avoir un problème de toute façon. Pour ce faire, vous pouvez créer des typedefs dans vos classes qui définissent les exceptions levées par diverses classes de modèles. Cela pense que le problème est comme toujours de l'aborder par la suite plutôt que de le concevoir dès le départ, et je pense que c'est cette surcharge qui est le véritable obstacle.
la source
Spécifications d'exception = nul, demandez à tout développeur Java de plus de 30 ans
la source