web-dev-qa-db-fra.com

Liste de diffusion obsolète en C ++ 11

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?

44
Peregring-lk

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).

48
Peter

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:

  • Les spécifications d'exception entraînent la fin du programme (ou plus précisément des gestionnaires de terminaison d'appel) si l'implémentateur n'a pas respecté la garantie de ne lever que les exceptions définies.
  • Ainsi, en appelant une méthode avec une spécification d'exception, vous, en tant qu'utilisateur de bibliothèque, rendez votre propre code plus susceptible de terminer l'échec/l'arrêt. Si la fonction de bibliothèque manque de mémoire (std :: bad_alloc), vous n'aurez pas la chance d'attraper, mais vous serez arrêté à la place.
  • Ainsi, l'objectif initial de communiquer les options de défaillance les plus probables et de vous demander en tant qu'utilisateur de les gérer n'a pas été atteint.
  • En tant qu'implémenteur de l'autre côté, vous ne pouvez plus vraiment appeler d'autres méthodes qui n'ont pas de spécifications d'exception, car cela pourrait vous obliger à mettre fin à vos appelants. Un endroit terrible où être.

La conclusion est que C++ aurait dû suivre le chemin que Java l'a fait:

  • Si vous appelez une méthode avec spécification d'exception et que vous avez vous-même une spécification d'exception, vous devez intercepter l'exception ou la spécifier dans votre propre spécification d'exception.
  • Le compilateur applique cela et aucun autre effet d'exécution.

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 ).

7
Christopher Oezbek

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.

4
dupersuper