En complément de la réponse de @SebastianRedl : pourquoi vous aurez besoin de noexcept
?
noexcept et std::vector
Comme vous le savez peut-être, un vector
a sa capacité. S'il est plein lorsque push_back
Il allouera une plus grande mémoire, copiera (ou déplacera depuis C++11) tous les éléments existants vers le nouveau tronc, puis ajoutera le nouvel élément à l'arrière.
Mais que se passe-t-il si une exception est levée lors de l'allocation de la mémoire ou de la copie de l'élément dans le nouveau tronc ?
-
Si une exception est levée pendant l'allocation de la mémoire, le vecteur est dans son état d'origine. Il suffit de relancer l'exception et de laisser l'utilisateur s'en occuper.
-
Si une exception est levée pendant la copie d'éléments existants, tous les éléments copiés seront détruits en appelant le destructeur, le coffre alloué sera libéré et l'exception levée sera gérée par le code de l'utilisateur. (1)
Après avoir tout détruit, le vecteur revient à son état d'origine. Il est maintenant possible de lancer une exception pour permettre à l'utilisateur de la gérer, sans fuite de ressources.
noexcept et move
À l'ère de C++ 11, nous disposons d'une arme puissante appelée move
. Il nous permet de voler les ressources des objets inutilisés. std::vector utilisera move
lorsqu'il doit augmenter (ou diminuer) la capacité, tant que les move
L'opération est pas d'exception .
Supposons qu'une exception se produise pendant le déplacement, le tronc précédent n'est pas le même qu'avant. move
se produit : les ressources sont volées, ce qui laisse le vecteur dans une situation d'urgence. cassé État. L'utilisateur ne peut pas gérer l'exception car tout est dans un état non déterministe.
C'est pourquoi std::vector
s'appuie sur move constructor
être pas d'exception .
Il s'agit d'une démonstration de la manière dont le code client s'appuierait sur les éléments suivants noexcept
en tant que spécification d'interface. Si, par la suite, le noexcept
n'est pas respectée, tout code qui en dépend précédemment sera cassé.
Pourquoi ne pas simplement marquer toutes les fonctions comme noexcept
?
Réponse courte : il est difficile d'écrire du code sans risque d'exception.
Réponse longue : noexcept
fixer une limite stricte aux développeurs qui mettent en œuvre l'interface. Si vous souhaitez supprimer l'interface noexcept
à partir d'une interface, le code client peut être cassé comme dans l'exemple du vecteur donné ci-dessus ; mais si vous voulez rendre une interface noexcept
Vous êtes libre de le faire à tout moment.
Ainsi, ce n'est qu'en cas de nécessité que l'on peut marquer une interface comme noexcept
.
Dans le cadre de la Going Native 2013 (en anglais) Scott Meyers a parlé de la situation décrite ci-dessus, à savoir que sans l'aide de l'Union européenne, il n'est pas possible de faire des économies. noexcept
la cohérence d'un programme est mise à mal.
J'ai également écrit un blog à ce sujet : https://xinhuang.github.io/posts/2013-12-31-when-to-use-noexcept-and-when-to-not.html