15 Exception handling [except]

15.4 Exception specifications [except.spec]

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:

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,

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:

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 ]