27 votes

Pourquoi le noexcept de C ++ 0x est-il vérifié dynamiquement?

Je suis curieux de connaître la raison d'être de noexcept dans le FCD C ++ 0x . throw(X) été déprécié, mais noexcept semble faire la même chose. Y a-t-il une raison pour laquelle noexcept n'est pas vérifié au moment de la compilation? Il semble qu'il serait préférable que ces fonctions soient vérifiées statiquement qu'elles appellent uniquement des fonctions de lancement dans un bloc try .

25voto

Vicente Botet Escriba Points 2954

Si je me souviens jeter a été abandonné car il n'y a aucun moyen de spécifier toutes les exceptions à une fonction de modèle peut jeter. Même pour les non-modèle des fonctions que vous aurez besoin de la jeter clause parce que vous avez ajouté quelques traces.

D'autre part, le compilateur peut optimiser le code qui n'est pas de lancer des exceptions. Voir "Le Débat sur noexcept, Partie I" (de même que certaines parties II et III) pour une discussion détaillée. Le point principal semble être:

La vaste expérience des deux dernières décennies montre que, dans la pratique, seuls les deux formes d'exceptions spécifications sont utiles:

  • L'absence d'un manifeste spécification d'exception, qui désigne une fonction qui permet de lancer n'importe quel type d'exception:

    int func(); //might throw any exception
    
  • Une fonction qui n'a jamais lancers. Une telle fonction peut être indiqué par un throw() spécifications:

    int add(int, int) throw(); //should never throw any exception
    

21voto

spraff Points 10492

En gros, c'est un linker problème, le comité des normes a été réticents à briser l'ABI. (Si ça ne tenait qu'à moi, je le ferais, tout ce qu'il faut vraiment est la bibliothèque de la recompilation, nous avons cette situation déjà avec du fil d'habilitation, et c'est gérable.)

Considérez comment cela allait tourner. Supposons que les exigences ont été

  1. chaque destructeur est implicitement noexcept(true)
    • Sans doute, ce devrait être une exigence stricte. Jeter les destructeurs sont toujours un bug.
  2. chaque extern "C" est implicitement noexcept(true)
    • Même argument nouveau: les exceptions en C-land sont toujours un bug.
  3. tous les autres fonction est implicitement noexcept(false) , sauf indication contraire
  4. un noexcept(true) fonction doit placer tous ses noexcept(false) des appels en try{}catch(...){}
    • Par analogie, un const méthode ne peut pas appeler un non-const méthode.
  5. Cet attribut doit se manifester comme un type distinct dans la résolution de surcharge, le pointeur de la fonction de compatibilité, etc.

Semble raisonnable, non?

Pour ce faire, l'éditeur de liens doit faire la distinction entre noexcept(true) et noexcept(false) versions de fonctions, comme vous pouvez le surcharge de const et const versions de fonctions membres.

Alors qu'est-ce que cela signifie pour nom-namgling? Pour être rétro-compatible avec l'objet existant code nous demandons que tous les noms sont interprétés comme noexcept(false) supplémentaire avec une déformation de l' noexcept(true) versions.

Ceci impliquerait que nous ne pouvons pas le lien avec les destructeurs, à moins que l'en-tête est modifié de les marquer comme noexcept(false)

  • ce serait briser la compatibilité descendante,
  • cela a sans doute devrait être impossible, voir le point 1.

J'ai parlé à un membre du comité en personne à ce sujet et il a dit que c'était une décision précipitée, motivés principalement par une contrainte sur les opérations de déplacement dans des contenants (vous pourriez finir avec les éléments manquants après un lancer, ce qui viole la garantie de base). Rappelez-vous, c'est un homme qui a déclaré la philosophie de conception est que la faute intolérants code est bon. Tirer vos propres conclusions.

Comme je l'ai dit, je l'aurais cassé l'ABI, de préférence à la rupture de la langue. noexcept n'est qu'une amélioration marginale sur le vieux chemin. La vérification statique est toujours la meilleure.

8voto

outis Points 39377

Notez que noexcept vérifie une exception levée par un dynamic_cast et typeid appliqué à un pointeur null , ce qui ne peut être fait qu'à Durée. D'autres tests peuvent en effet être effectués lors de la compilation.

5voto

AshleysBrain Points 11439

Comme d'autres réponses ont indiqué, des déclarations telles que dynamic_casts pouvez éventuellement jeter, mais ne peut être vérifié au moment de l'exécution, de sorte que le compilateur ne peut pas dire de façon certaine au moment de la compilation.

Cela signifie qu'au moment de la compilation, le compilateur peut soit laisser aller (ie. ne compile pas temps de vérifier), warn, ou rejeter, en bloc (ce qui ne serait pas utile). Que les feuilles d'avertissement que la seule chose raisonnable pour le compilateur de le faire.

Mais c'est pas encore vraiment utile - supposons que vous avez un dynamic_cast qui, pour quelque raison que ce soit, que vous connaissez, ne jamais échouer et lève une exception parce que votre programme est écrit. Le compilateur n'a probablement pas savoir qui et lance un avertissement, qui devient du bruit, ce qui probablement a été désactivé par le programmeur pour être inutile, la négation de la point de l'avertissement.

Un problème similaire est si vous avez une fonction qui n'est pas spécifié avec noexcept (ie. peut lancer des exceptions) que vous voulez appeler de nombreuses fonctions, certains noexcept, d'autres non. Vous savez que la fonction ne jetez jamais dans les circonstances appelé par l' noexcept fonctions, mais le compilateur n'a pas: plus inutiles les avertissements.

Donc il n'est pas utile pour le compilateur pour appliquer cela au moment de la compilation. C'est plus dans le domaine de l'analyse statique, qui ont tendance à être plus pointilleux et lancer des mises en garde pour ce genre de chose.

3voto

Winston Ewert Points 17746

Considérons une fonction

void fn() noexcept
{
   foo();
   bar();
}

Pouvez-vous statiquement vérifier s'il est correct? Vous devez savoir si foo bar ou vont lancer des exceptions. Vous pouvez forcer tous les appels de fonctions à l'intérieur d'un try{} bloc, quelque chose comme cela

void fun() noexcept
{
    try
    {
         foo();
         bar();
    }
    catch(ExceptionType &)
    {
    }
}

Mais c'est faux. Nous n'avons aucun moyen de savoir que foo et bar ne lancer ce type d'exception. Afin de nous assurer d'attraper tout ce que nous avions besoin d'utiliser de "...". Si vous attraper quoi que ce soit, qu'allez-vous faire avec toutes les erreurs que vous attraper? Si une erreur inattendue se pose ici, la seule chose à faire est d'abandonner le programme. Mais c'est essentiellement ce que le moment de l'exécution fourni par défaut va faire.

En bref, en fournissant suffisamment de détails pour prouver qu'une fonction donnée ne sera jamais jeter le mauvais exceptions serait de produire des verbose code dans les cas où le compilateur ne peut pas être sûr de savoir si ou non la fonction jeter le mauvais type. L'utilité de la statique de la preuve n'est probablement pas la peine de l'effort.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X