Qu'est-ce que noexcept utile pour?
J'ai vu que C++ 11 a ajouté le mot-clé noexcept
. Mais je ne comprends pas vraiment pourquoi est-ce utile.
Si la fonction lance quand elle n'est pas censée lancer - pourquoi voudrais-je que le programme plante?
Alors quand devrais-je l'utiliser?
Aussi, comment cela fonctionnera-t-il avec la compilation avec / Eha et l'utilisation de _set_se_translator
? Cela signifie que n'importe quelle ligne de code peut lancer une exception C++ - car elle pourrait lancer une exception SEH (en raison de l'accès à la mémoire protégée) et elle sera traduite à des exceptions c++.
Que se passera-t-il alors?
2 réponses
L'utilisation principale de {[1] } est pour les algorithmes génériques, par exemple, lors du redimensionnement d'un std::vector<T>
: pour un algorithme efficace, il est nécessaire de savoir à l'avance qu'aucun des mouvements ne sera lancé. Si les éléments en mouvement peuvent lancer, les éléments doivent être copiés à la place. En utilisant l'opérateur noexcept(expr)
, l'implémentation de la bibliothèque peut déterminer si une opération particulière peut être lancée. La propriété des opérations qui ne lancent pas fait partie du contrat: si ce contrat est violé, tous les paris sont désactivés et il peut y avoir aucun moyen de récupérer un état valide. Renflouer avant de causer plus de dégâts est le choix naturel.
Pour propager les connaissances sur les opérations noexcept
Ne pas lancer, il est également nécessaire de déclarer les fonctions en tant que telles. À cette fin, vous pouvez utiliser noexcept
, throw()
, ou noexcept(expr)
, avec une expression constante. Le formulaire utilisant une expression est nécessaire lors de l'implémentation d'une structure de données générique: avec l'expression, il peut être déterminé si l'une des opérations dépendantes du type peut lancer une exception.
Par exemple std::swap()
est déclaré quelque chose comme ceci:
template <typename T>
void swap(T& o1, T& o2) noexcept(noexcept(T(std::move(o1)) &&
noexcept(o1 = std::move(o2)));
Basé sur noexcept(swap(a, b))
la bibliothèque peut alors choisir des implémentations différentes et efficaces de certaines opérations: si elle peut simplement swap()
sans risquer une exception, elle peut temporairement violer les invariants et les récupérer plus tard. Si une exception peut être levée, la bibliothèque peut avoir besoin de copier des objets plutôt que de les déplacer.
Il est peu probable que l'implémentation de la bibliothèque C++ standard dépendra de nombreuses opérations pour être noexcept(true)
. Les opérations probablement qu'il vérifiera sont principalement celles impliquées dans le déplacement d'objets, c'est-à-dire:
- le destructeur d'une classe (notez que les destructeurs sont par défaut
noexcept(true)
même sans aucune déclaration; si vous avez destructor que peut lancer , vous devez le déclarer comme tel, par exemple:T::~T() noexcept(false)
). - les opérateurs de déplacement, c'est-à-dire déplacer la construction (
T::T(T&&)
) et déplacer l'affectation (T::operator=(T&&)
). - le type est
swap()
opérations ({[17] } et éventuellement la version du membreT::swap(T&)
).
Si l'une de ces opérations s'écarte de la valeur par défaut, vous devez la déclarer en conséquence pour obtenir l'implémentation la plus efficace. Les versions générées de ces opérations déclarent si elles lancent des exceptions en fonction des opérations respectives utilisées pour les membres et les bases.
Bien que je puisse imaginer que certaines opérations puissent être ajoutées à l'avenir ou par certaines bibliothèques spécifiques, Je ne le ferais probablement pas opérations de déclaration comme noexcept
pour l'instant. Si d'autres fonctions apparaissent qui font une différence en étant noexcept
, elles peuvent être déclarées (et éventuellement modifiées si nécessaire) à l'avenir.
La raison pour laquelle le programme peut planter est que noexcept
indique à l'optimiseur que votre code ne sera pas lancé. Si c'est le cas - eh bien, il n'y a aucun moyen de prédire ce qui se passera avec le code optimisé.
Comme pour MSVC++, vous devez vérifier ce qui se passe quand ils implémentent noexcept
. D'un point de vue Standard, SEH est un comportement indéfini. L'accès à la mémoire protégée peut déjà planter en ce moment.