Tout comme je peux le voir dans cppreference , les listes de déclarations "throw" classiques sont désormais obsolètes en C++ 11. Quelle est la raison de quitter ce mécanisme et comment devrais-je avoir à spécifier quelles exceptions lève une fonction de la mienne?
Pour un raisonnement plus détaillé, voir: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3051.html
Comme indiqué dans le commentaire de l'organisme national ci-dessus, les spécifications d'exception ne se sont pas révélées utiles dans la pratique. Il existe de nombreuses discussions sur les problèmes liés aux spécifications d'exception en C++ (voir, par exemple, [Sutter02], [Boost03]), mais les principaux problèmes sont les suivants:
- Vérification au moment de l'exécution: les spécifications d'exception C++ sont vérifiées au moment de l'exécution plutôt qu'au moment de la compilation, elles n'offrent donc aucune garantie de programmation que toutes les exceptions ont été gérées. Le mode d'échec d'exécution (appel à std :: inattendu ()) ne se prête pas à la récupération.
- Surcharge d'exécution: la vérification au moment de l'exécution nécessite que le compilateur produise du code supplémentaire qui entrave également les optimisations.
- Inutilisable dans le code générique: dans le code générique, il n'est généralement pas possible de savoir quels types d'exceptions peuvent être levées à partir d'opérations sur les arguments de modèle, de sorte qu'une spécification d'exception précise ne peut pas être écrite.
En pratique, seules deux formes de garanties de levée d'exceptions sont utiles: une opération peut lever une exception (n'importe quelle exception) ou une opération ne lèvera jamais aucune exception. La première est exprimée en omettant complètement la spécification d'exception, tandis que la seconde peut être exprimée comme throw () mais l'est rarement, pour des raisons de performances.
[N3050] introduit un nouveau type de spécification d'exception, noexcept, le spécifie que la fonction ne lèvera aucune exception. Contrairement à throw (), noexcept ne nécessite pas que le compilateur introduise du code pour vérifier si une exception est levée. Au contraire, si une fonction spécifiée comme noexcept est quittée via une exception, le résultat est un appel à std :: terminate ().
Avec l'introduction de noexcept, les programmeurs peuvent désormais exprimer les deux types de garanties d'exception qui sont utiles dans la pratique, sans frais supplémentaires. Cet article propose donc de déprécier les spécifications d'exceptions "dynamiques", c'est-à-dire celles qui sont écrites comme throw (type-id-listopt).
La réponse que Peter a donnée ne touche pas au problème réel des spécifications d'exception pour l'implémenteur et l'utilisateur:
La conclusion est que C++ aurait dû suivre le chemin que Java l'a fait:
Noexcept (depuis C++ 11) souffre de la même erreur conceptuelle, car il entraînera également l'arrêt de l'exécution si la spécification n'est pas également respectée, c'est-à-dire une méthode qui a été déclarée non. Cela rend noexcept
impossible à utiliser pour quoi que ce soit de grave mais les cas les plus contenus ( les constructeurs de déplacement me viennent à l'esprit ).
Ils produisent du code plus lent et plus gros, car libc ++ doit vérifier si une exception se propageant hors d'une fonction viole sa spécification d'exception et appelle std::unexpected
. Ceci n'est presque jamais utile et est pire que de simplement documenter les exceptions qu'une fonction vous lance.