Namespaces
Variants

noexcept specifier (since C++11)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous
Exceptions
try block
Throwing exceptions
Handling exceptions
Exception specification
noexcept specification (C++11)
dynamic specification ( until C++17* )
noexcept operator (C++11)

Spécifie si une fonction peut lever des exceptions.

Table des matières

Syntaxe

noexcept (1)
noexcept( expression ) (2)
throw() (3) (obsolète en C++17)
(supprimé en C++20)
1) Identique à noexcept(true)
2) Si expression s'évalue à true , la fonction est déclarée comme ne levant aucune exception. Une ( suivant noexcept fait toujours partie de cette forme (elle ne peut jamais commencer un initialiseur).
3) Identique à noexcept(true) (voir spécification d'exception dynamique pour sa sémantique avant C++17)
expression - expression constante contextuellement convertie de type bool

Explication

La spécification noexcept ne fait pas partie du type de fonction (tout comme la spécification d'exception dynamique ) et ne peut apparaître que comme partie d'un déclarateur lambda ou d'un déclarateur de fonction de niveau supérieur lors de la déclaration de fonctions, de variables, de membres de données non statiques de type fonction, de pointeurs vers des fonctions, de références vers des fonctions, ou de pointeurs vers des fonctions membres, et également lors de la déclaration d'un paramètre ou d'un type de retour dans l'une de ces déclarations qui s'avère être un pointeur ou une référence vers une fonction. Elle ne peut pas apparaître dans une déclaration de typedef ou alias de type .

void f() noexcept; // la fonction f() ne lance pas
void (*fp)() noexcept(false); // fp pointe vers une fonction qui peut lancer
void g(void pfa() noexcept);  // g prend un pointeur vers une fonction qui ne lance pas
// typedef int (*pf)() noexcept; // erreur
(jusqu'en C++17)

La spécification noexcept fait partie du type de fonction et peut apparaître comme partie de tout déclarateur de fonction .

(depuis C++17)

Toute fonction en C++ est soit non-throwing soit potentially throwing :

  • potentially-throwing fonctions sont :
(jusqu'à C++17)
  • fonctions déclarées avec le spécificateur noexcept dont l' expression évalue à false
  • fonctions déclarées sans le spécificateur noexcept sauf pour
  • un constructeur pour une base ou membre que la définition implicite du constructeur appellerait est potentiellement lanceur (voir ci-dessous)
  • une sous-expression d'une telle initialisation, telle qu'une expression d'argument par défaut, est potentiellement lanceur (voir ci-dessous)
  • un initialiseur de membre par défaut (pour le constructeur par défaut uniquement) est potentiellement lanceur (voir ci-dessous)
  • opérateurs de comparaison qui sont définis par défaut lors de leur première déclaration, sauf si l'invocation de tout opérateur de comparaison dans la définition implicite est potentiellement levée (voir ci-dessous)
(depuis C++20)
  • les fonctions non levantes sont toutes les autres (celles avec le spécificateur noexcept dont l'expression évalue à true ainsi que les destructeurs, les fonctions membres spéciales par défaut et les fonctions de désallocation)

Instanciations explicites peuvent utiliser le spécificateur noexcept, mais ce n'est pas obligatoire. S'il est utilisé, la spécification d'exception doit être la même que pour toutes les autres déclarations. Un diagnostic n'est requis que si les spécifications d'exception ne sont pas identiques au sein d'une même unité de traduction.

Les fonctions qui ne diffèrent que par leur spécification d'exception ne peuvent pas être surchargées (tout comme le type de retour, la spécification d'exception fait partie du type de fonction, mais ne fait pas partie de la signature de fonction) (depuis C++17) .

void f() noexcept;
void f(); // erreur : spécification d'exception différente
void g() noexcept(false);
void g(); // ok, les deux déclarations pour g sont potentiellement levantes

Les pointeurs (y compris les pointeurs vers des fonctions membres) vers des fonctions non levantes d'exception peuvent être assignés ou utilisés pour initialiser (jusqu'à C++17) sont implicitement convertibles en (depuis C++17) des pointeurs vers des fonctions potentiellement levantes d'exception, mais pas l'inverse.

void ft(); // potentiellement levante
void (*fn)() noexcept = ft; // erreur

Si une fonction virtuelle est non-lancée, toutes les déclarations, y compris la définition, de chaque surcharge doivent également être non-lancées, à moins que la surcharge ne soit définie comme supprimée :

struct B
{
    virtual void f() noexcept;
    virtual void g();
    virtual void h() noexcept = delete;
};
struct D: B
{
    void f();          // incorrect : D::f est potentiellement levée d'exception, B::f est non levée
    void g() noexcept; // OK
    void h() = delete; // OK
};

Les fonctions non levantes sont autorisées à appeler des fonctions potentiellement levantes. Chaque fois qu'une exception est levée et que la recherche d'un gestionnaire rencontre le bloc le plus externe d'une fonction non levante, la fonction std::terminate est appelée :

extern void f(); // potentiellement levante d'exceptions
void g() noexcept
{
    f();      // valide, même si f lève une exception
    throw 42; // valide, équivaut effectivement à un appel à std::terminate
}

La spécification d'exception d'une spécialisation de fonction template n'est pas instanciée avec la déclaration de la fonction ; elle est instanciée uniquement quand nécessaire (tel que défini ci-dessous).

La spécification d'exception d'une fonction membre spéciale implicitement déclarée n'est également évaluée que lorsque nécessaire (en particulier, la déclaration implicite d'une fonction membre d'une classe dérivée ne nécessite pas que la spécification d'exception d'une fonction membre de base soit instanciée).

Lorsque la spécification noexcept d'une spécialisation de fonction modèle est nécessaire , mais n'a pas encore été instanciée, les noms dépendants sont recherchés et tous les modèles utilisés dans l' expression sont instanciés comme pour la déclaration de la spécialisation.

Une spécification noexcept d'une fonction est considérée comme nécessaire dans les contextes suivants :

  • dans une expression, où la fonction est sélectionnée par résolution de surcharge
  • la fonction est odr-used
  • la fonction serait odr-used mais apparaît dans un opérande non évalué
template<class T>
T f() noexcept(sizeof(T) < 4);
int main()
{
    decltype(f<void>()) *p; // f non évaluée, mais la spécification noexcept est nécessaire
                            // erreur car l'instanciation de la spécification noexcept
                            // calcule sizeof(void)
}
  • la spécification est nécessaire pour comparer à une autre déclaration de fonction (par exemple, sur un surchargeur de fonction virtuelle ou sur une spécialisation explicite d'un modèle de fonction)
  • dans une définition de fonction
  • la spécification est nécessaire car une fonction membre spéciale par défaut doit la vérifier afin de décider de sa propre spécification d'exception (cela se produit uniquement lorsque la spécification de la fonction membre spéciale par défaut est, elle-même, nécessaire).

Définition formelle de potentially-throwing expression (utilisée pour déterminer la spécification d'exception par défaut des destructeurs, constructeurs et opérateurs d'assignation comme décrit ci-dessus) :

Une expression e est potentiellement-lancée si :

  • e est un appel de fonction à une fonction, un pointeur de fonction, ou un pointeur de fonction membre qui est potentiellement levante , sauf si e est une expression constante de base (jusqu'en C++17)
  • e effectue un appel implicite à une fonction potentiellement levante (telle qu'un opérateur surchargé, une fonction d'allocation dans une new -expression, un constructeur pour un argument de fonction, ou un destructeur si e est une expression complète)
  • e est une throw -expression
  • e est un dynamic_cast qui convertit un type référence polymorphe
  • e est une expression typeid appliquée à un pointeur déréférencé vers un type polymorphe
  • e a une sous-expression immédiate qui est potentiellement levante
struct A
{
    A(int = (A(5), 0)) noexcept;
    A(const A&) noexcept;
    A(A&&) noexcept;
    ~A();
};
struct B
{
    B() throw();
    B(const B&) = default; // la spécification d'exception implicite est noexcept(true)
    B(B&&, int = (throw Y(), 0)) noexcept;
    ~B() noexcept(false);
};
int n = 7;
struct D : public A, public B
{
    int * p = new int[n];
    // D::D() potentiellement levante à cause de l'opérateur new
    // D::D(const D&) non levante
    // D::D(D&&) potentiellement levante : l'argument par défaut du constructeur de B peut lever
    // D::~D() potentiellement levante
    // note : si A::~A() était virtuel, ce programme serait mal formé car un surchargeur
    // d'une fonction virtuelle non levante ne peut pas être potentiellement levante
};

Notes

L'un des usages de l'expression constante est (avec l' noexcept opérateur ) de définir des modèles de fonction qui déclarent noexcept pour certains types mais pas pour d'autres.

Notez qu'une spécification noexcept sur une fonction n'est pas une vérification à la compilation ; c'est simplement une méthode permettant au programmeur d'informer le compilateur si une fonction doit lever des exceptions ou non. Le compilateur peut utiliser cette information pour activer certaines optimisations sur les fonctions non levantes ainsi que pour activer l' noexcept opérateur , qui peut vérifier à la compilation si une expression particulière est déclarée comme pouvant lever des exceptions. Par exemple, les conteneurs tels que std::vector déplaceront leurs éléments si le constructeur de déplacement des éléments est noexcept , et les copieront sinon (sauf si le constructeur de copie n'est pas accessible, mais qu'un constructeur de déplacement potentiellement levant l'est, auquel cas la garantie d'exception forte est abandonnée).

Obsolète

noexcept est une version améliorée de throw ( ) , qui est dépréciée en C++11. Contrairement à throw ( ) pré-C++17, noexcept n'appellera pas std::unexpected , pourra ou non dérouler la pile, et appellera std::terminate , ce qui permet potentiellement au compilateur d'implémenter noexcept sans la surcharge d'exécution de throw ( ) . Depuis C++17, throw ( ) est redéfini comme étant exactement équivalent à noexcept ( true ) .

Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_noexcept_function_type 201510L (C++17) Rendre les spécifications d'exception partie du système de type

Mots-clés

noexcept , throw (depuis C++17) (jusqu'à C++20)

Exemple

// whether foo is declared noexcept depends on if the expression
// T() will throw any exceptions
template<class T>
void foo() noexcept(noexcept(T())) {}
void bar() noexcept(true) {}
void baz() noexcept { throw 42; } // noexcept is the same as noexcept(true)
int main() 
{
    foo<int>(); // noexcept(noexcept(int())) => noexcept(true), so this is fine
    bar(); // fine
    baz(); // compiles, but at runtime this calls std::terminate
}

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement corrigé
CWG 1330 C++11 une spécification d'exception pouvait être instanciée de manière anticipée elle n'est instanciée que si nécessaire
CWG 1740 C++11 un ( suivant noexcept pouvait démarrer un initialiseur il ne peut faire partie que
d'une spécification noexcept
CWG 2039 C++11 seule l'expression avant conversion devait être constante la conversion doit également être
valide dans une expression constante

Voir aussi

noexcept opérateur (C++11) détermine si une expression lève des exceptions
Spécification d'exception dynamique (jusqu'à C++17) spécifie les exceptions levées par une fonction (obsolète en C++11)
throw expression signale une erreur et transfère le contrôle au gestionnaire d'erreurs
convertit l'argument en xvalue si le constructeur de déplacement ne lève pas d'exception
(modèle de fonction)