2015-02-26 1 views
2

En C++, si une méthode peut lancer uniquement parce que les invariants de la classe ne sont pas conservés, dois-je le marquer noexcept? Par exemple, une liste a un pointeur sur le lien, qui doit être nullptr ou un pointeur correct, et une méthode déréférence ce pointeur. Empêche-t-il d'utiliser noexcept?Invariants et noexcept

+0

Possible UB n'empêche pas l'utilisation de 'noexcept'. –

+1

Le déréférencement d'un pointeur non valide n'est pas défini et n'entraîne pas d'exception C++. – molbdnilo

+0

@molbdnilo Comme il n'est pas défini, il peut provoquer une exception C++. Alors encore, il pourrait ne pas; il pourrait juste corrompre l'espace d'espace libre, de sorte que votre programme se bloque dans un endroit totalement indépendant. (Visual Studios a une option pour convertir l'accès en dehors de la mémoire mappée en une exception.Mais bien sûr, un pointeur invalide ne pointera pas nécessairement en dehors de la mémoire mappée.Vous ne pouvez donc pas écrire du code qui dépend de cette exception.Et dans la plupart des cas, vous aurez besoin d'abandonner, plutôt que de lancer une exception de toute façon.) –

Répondre

0

Si une fonction peut sortir par une exception, vous ne devriez pas marquer nothrow; nothrow est une garantie qu'il jamais se termine via une exception . Il est essentiel qu'il y ait au moins quelques fonctions que ne lance jamais (et je ne dis jamais) si vous voulez écrire du code de sécurité.

Si les invariants de classe ne peuvent pas être conservés, vous ne devez pas lancer une exception ; Tout ce que vous pouvez raisonnablement faire, c'est annuler le processus. Ne pas confondre cela avec un constructeur qui ne peut pas établir les invariants, cependant; son amende à jeter alors, puisqu'il n'y aura plus d'objet ensuite qui ne soit pas conforme aux invariants. En outre, dans certains cas , il est valide de définir un ensemble plus faible d'invariants qui se conservent après le lancement . Dites juste assez pour garantir que l'objet peut être détruit en toute sécurité. Cela dépend de l'application (et de la façon dont la conception gère les exceptions ). Mais ces fonctions ne peuvent pas être déclarées nothrow. En ce qui concerne votre exemple concret: si l'invariant est soit un pointeur correct soit un pointeur nul, il n'y a aucun moyen de le tester et d'obtenir une exception quand même. Si le pointeur n'est pas valide (ne pointe pas vers un objet valide du type et n'est pas null), vous avez un comportement non défini. Tout peut arriver, et sur les systèmes réels, tout se passe si vous déréférencer le pointeur.

0

Si une fonction émet une exception pour signaler un problème, elle ne doit pas être déclarée noexcept. Ce serait violer, en effet, le contrat qu'il promet de satisfaire.

Qu'il déclenche ou non une exception, il est également recommandé que l'objet conserve son invariant. La pratique habituelle est que tous les constructeurs établissent un invariant et que toutes les autres fonctions membres maintiennent cet invariant jusqu'à ce que l'objet soit détruit (et que le destructeur soit invoqué).

Si une fonction déréférence un nullptr, son comportement est indéfini. Il n'est pas nécessaire de lancer une exception.

0

Si une méthode peut déclencher une exception lors du déréférencement d'un pointeur NULL, elle ne doit pas être marquée noexcept. Si vous voulez vraiment que ce soit noexcept, vous devriez tester le pointeur sur null (et retourner une valeur spéciale) avant de le déréférencer. Par exemple

if (pt == NULL) return NULL; 
// do use *pt or pt->xxx 
+1

La fonction vérifie que le pointeur n'est pas nul et le déréférence. Et l'invariant est que le pointeur est soit nul ou correct. Alors si ce n'est pas correct, c'est un comportement non défini? Donc, il jette seulement à cause de UB, et peut être marqué surexcept? – statnik

+0

@statnik Je ne lance probablement pas du tout. Il est impossible (ou presque) de déterminer si un pointeur est valide ou non; Si vous écrivez via un pointeur invalide, le résultat le plus commun est que certains autres objets seront corrompus, ou que vous allez corrompre l'espace libre. Les deux sont susceptibles de faire planter le programme quelque temps plus tard, dans un code totalement indépendant. –