A function declaration lists exceptions that its function might directly or indirectly throw by using an exception-specification as a suffix of its declarator.
exception-specification: dynamic-exception-specification noexcept-specification
dynamic-exception-specification: throw ( type-id-listopt )
type-id-list: type-id ...opt type-id-list , type-id ...opt
noexcept-specification: noexcept ( constant-expression ) noexcept
In a noexcept-specification, the constant-expression, if supplied, shall be a constant expression ([expr.const]) that is contextually converted to bool (Clause [conv]). A noexcept-specification noexcept is equivalent to noexcept(true). A ( token that follows noexcept is part of the noexcept-specification and does not commence an initializer ([dcl.init]).
An exception-specification shall appear only on a function declarator for a function type, pointer to function type, reference to function type, or pointer to member function type that is the top-level type of a declaration or definition, or on such a type appearing as a parameter or return type in a function declarator. An exception-specification shall not appear in a typedef declaration or alias-declaration. [ Example:
void f() throw(int); // OK void (*fp)() throw (int); // OK void g(void pfa() throw(int)); // OK typedef int (*pf)() throw(int); // ill-formed
— end example ]
A type denoted in an exception-specification shall not denote an incomplete type or an rvalue reference type. A type denoted in an exception-specification shall not denote a pointer or reference to an incomplete type, other than cv void*. A type cv T, “array of T”, or “function returning T” denoted in an exception-specification is adjusted to type T, “pointer to T”, or “pointer to function returning T”, respectively.
Two exception-specifications are compatible if:
both are non-throwing (see below), regardless of their form,
both have the form noexcept(constant-expression) and the constant-expressions are equivalent, or
both are dynamic-exception-specifications that have the same set of adjusted types.
If any declaration of a function has an exception-specification that is not a noexcept-specification allowing all exceptions, all declarations, including the definition and any explicit specialization, of that function shall have a compatible exception-specification. If any declaration of a pointer to function, reference to function, or pointer to member function has an exception-specification, all occurrences of that declaration shall have a compatible exception-specification In an explicit instantiation an exception-specification may be specified, but is not required. If an exception-specification is specified in an explicit instantiation directive, it shall be compatible with the exception-specifications of other declarations of that function. A diagnostic is required only if the exception-specifications are not compatible within a single translation unit.
If a virtual function has an exception-specification, all declarations, including the definition, of any function that overrides that virtual function in any derived class shall only allow exceptions that are allowed by the exception-specification of the base class virtual function. [ Example:
struct B { virtual void f() throw (int, double); virtual void g(); }; struct D: B { void f(); // ill-formed void g() throw (int); // OK };
The declaration of D::f is ill-formed because it allows all exceptions, whereas B::f allows only int and double. — end example ] A similar restriction applies to assignment to and initialization of pointers to functions, pointers to member functions, and references to functions: the target entity shall allow at least the exceptions allowed by the source value in the assignment or initialization. [ Example:
class A { /* ... */ }; void (*pf1)(); // no exception specification void (*pf2)() throw(A); void f() { pf1 = pf2; // OK: pf1 is less restrictive pf2 = pf1; // error: pf2 is more restrictive }
— end example ]
In such an assignment or initialization, exception-specifications on return types and parameter types shall be compatible. In other assignments or initializations, exception-specifications shall be compatible.
An exception-specification can include the same type more than once and can include classes that are related by inheritance, even though doing so is redundant. [ Note: An exception-specification can also include the class std::bad_exception ([bad.exception]). — end note ]
A function is said to allow an exception of type E if the constant-expression in its noexcept-specification evaluates to false or its dynamic-exception-specification contains a type T for which a handler of type T would be a match ([except.handle]) for an exception of type E.
Whenever an exception is thrown and the search for a handler ([except.handle]) encounters the outermost block of a function with an exception-specification that does not allow the exception, then,
if the exception-specification is a dynamic-exception-specification, the function std::unexpected() is called ([except.unexpected]),
otherwise, the function std::terminate() is called ([except.terminate]).
[ Example:
class X { }; class Y { }; class Z: public X { }; class W { }; void f() throw (X, Y) { int n = 0; if (n) throw X(); // OK if (n) throw Z(); // also OK throw W(); // will call std::unexpected() }
— end example ]
[ Note: A function can have multiple declarations with different non-throwing exception-specifications; for this purpose, the one on the function definition is used. — end note ]
The function unexpected() may throw an exception that will satisfy the exception-specification for which it was invoked, and in this case the search for another handler will continue at the call of the function with this exception-specification (see [except.unexpected]), or it may call std::terminate().
An implementation shall not reject an expression merely because when executed it throws or might throw an exception that the containing function does not allow. [ Example:
extern void f() throw(X, Y);
void g() throw(X) {
f(); // OK
}
the call to f is well-formed even though when called, f might throw exception Y that g does not allow. — end example ]
A function with no exception-specification or with an exception-specification of the form noexcept(constant-expression) where the constant-expression yields false allows all exceptions. An exception-specification is non-throwing if it is of the form throw(), noexcept, or noexcept(constant-expression) where the constant-expression yields true. A function with a non-throwing exception-specification does not allow any exceptions.
An exception-specification is not considered part of a function's type.
An inheriting constructor ([class.inhctor]) and an implicitly declared special member function (Clause [special]) have an exception-specification. If f is an inheriting constructor or an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f's implicit definition; f allows all exceptions if any function it directly invokes allows all exceptions, and f has the exception-specification noexcept(true) if every function it directly invokes allows no exceptions. [ Note: It follows that f has the exception-specification noexcept(true) if it invokes no other functions. — end note ] [ Note: An instantiation of an inheriting constructor template has an implied exception-specification as if it were a non-template inheriting constructor. — end note ] [ Example:
struct A { A(); A(const A&) throw(); A(A&&) throw(); ~A() throw(X); }; struct B { B() throw(); B(const B&) = default; // Declaration of B::B(const B&) noexcept(true) B(B&&) throw(Y); ~B() throw(Y); }; struct D : public A, public B { // Implicit declaration of D::D(); // Implicit declaration of D::D(const D&) noexcept(true); // Implicit declaration of D::D(D&&) throw(Y); // Implicit declaration of D::~D() throw(X, Y); };
Furthermore, if A::~A() or B::~B() were virtual, D::~D() would not be as restrictive as that of A::~A, and the program would be ill-formed since a function that overrides a virtual function from a base class shall have an exception-specification at least as restrictive as that in the base class. — end example ]
A deallocation function ([basic.stc.dynamic.deallocation]) with no explicit exception-specification is treated as if it were specified with noexcept(true).
An exception-specification is considered to be needed when:
in an expression, the function is the unique lookup result or the selected member of a set of overloaded functions ([basic.lookup], [over.match], [over.over]);
the function is odr-used ([basic.def.odr]) or, if it appears in an unevaluated operand, would be odr-used if the expression were potentially-evaluated;
the exception-specification is compared to that of another declaration (e.g., an explicit specialization or an overriding virtual function);
the function is defined; or
the exception-specification is needed for a defaulted special member function that calls the function. [ Note: A defaulted declaration does not require the exception-specification of a base member function to be evaluated until the implicit exception-specification of the derived function is needed, but an explicit exception-specification needs the implicit exception-specification to compare against. — end note ]
The exception-specification of a defaulted special member function is evaluated as described above only when needed; similarly, the exception-specification of a specialization of a function template or member function of a class template is instantiated only when needed.
In a dynamic-exception-specification, a type-id followed by an ellipsis is a pack expansion ([temp.variadic]).
[ Note: The use of dynamic-exception-specifications is deprecated (see Annex [depr]). — end note ]