# Dynamic exception specification

From cppreference.com
< cpp‎ | language

Lists the exceptions that a function might directly or indirectly throw.

### Syntax

`throw(` `)` | (1) | (deprecated in C++11)(removed in C++20)
`throw(`typeid, typeid, ...`)` | (2) | (deprecated in C++11)(removed in C++17)

1) Non-throwing dynamic exception specification | (until C++17)
1) Same as `noexcept(true)` | (since C++17)

2) Explicit dynamic exception specification

This specification may appear only on lambda-declarator or on a function declarator that is the top-level (until C++17) declarator of a function, variable, or non-static data member, whose type is a function type, a pointer to function type, a reference to function type, a pointer to member function type. It may appear on the declarator of a parameter or on the declarator of a return type.

    void f() throw(int); // OK: function declaration
    void (*pf)() throw (int); // OK: pointer to function declaration
    void g(void pfa() throw(int)); // OK: pointer to function parameter declaration
    typedef int (*pf)() throw(int); // Error: typedef declaration

### Explanation

If a function is declared with type `T` listed in its exception specification, the function may throw exceptions of that type or a type derived from it.

Incomplete types, pointers or references to incomplete types other than cv `void*`, and rvalue reference types are not allowed in the exception specification. Array and function types, if used, are adjusted to corresponding pointer types. parameter packs are allowed (since C++11).

If the function throws an exception of the type not listed in its exception specification, the function std::unexpected is called. The default function calls std::terminate, but it may be replaced by a user-provided function (via std::set_unexpected) which may call std::terminate or throw an exception. If the exception thrown from std::unexpected is accepted by the exception specification, stack unwinding continues as usual. If it isn't, but std::bad_exception is allowed by the exception specification, std::bad_exception is thrown. Otherwise, std::terminate is called.

### Potential exceptions

Each function `f`, pointer to function `pf`, and pointer to member function `pmf` has a set of potential exceptions, which consists of types that might be thrown. Set of all types indicates that any exception may be thrown. This set is defined as follows:

1) If the declaration of `f`, `pf`, or `pmf` uses `throw()`(deprecated) or noexcept, the set is empty.
2) Otherwise, if the declaration of `f`, `pf`, or `pmf` uses a dynamic exception specification(deprecated), the set consists of the types listed in that specification
3) Otherwise, the set is the set of all types

Note: for implicitly-declared special member functions (constructors, assignment operators, and destructors) and for the inheriting constructors, the set of potential exceptions is a combination of the sets of the potential exceptions of everything they would call: constructors/assignment operators/destructors of non-variant non-static data members, direct bases, and, where appropriate, virtual bases (including default argument expressions, as always)

Each expression `e` has a set of potential exceptions, which is the union of the sets of potential exceptions of all immediate subexpressions of `e` (including default argument expressions), combined with another set that depends on the form of `e`, as follows:

1) If `e` is a function call expression, and

- the function is named by an id-expression (either directly or as part of member access or pointer-to-member access expression), the set of potential exceptions of the named function is added to the list.
- if the function is named by an expression of type noexcept function or by an expression of type pointer to noexcept function, the set is empty
- otherwise, the set is the set of all types

2) If `e` calls a function implicitly (it's an operator expression and the operator is overloaded, it is a new-expression and the allocation function is overloaded, or it is a full expression and the destructor of a temporary is called), then the set is the set of that function.
3) If `e` is a throw-expression, the set is the exception that would be initialized by its operand, or the set of all types for the re-throwing throw-expression (with no operand)
4) If `e` is a dynamic_cast to a reference to a polymorphic type, the set consists of std::bad_cast
5) If `e` is a typeid applied to a polymorphic glvalue, the set consists of std::bad_typeid
6) If `e` is a new-expression with a non-constant size, the set consists of std::bad_array_new_length

    void f() throw(int);  // f()'s set is "int"
    void g();             // g()'s set is the set of all types
    struct A { A(); };    // "new A"'s set is the set of all types
    struct B { B() noexcept; }; // "B()"'s set is empty
    struct D() { D() throw (double); }; // new D's set is the set of all types

All implicitly-declared member functions (and inheriting constructors) have exception specifications, selected as follows:

- If the set of potential exceptions is the set of all types, the implicit exception specification is noexcept(false).
- Otherwise, If the set of potential exceptions is not empty, the implicit exception specification lists every type from the set
- Otherwise, the implicit exception specification is noexcept(true) and the function type is "noexcept function"

    struct A {
        A(int = (A(5), 0)) noexcept;
        A(const A&) throw();
        A(A&&) throw();
        ~A() throw(X);
    };
    struct B {
        B() throw();
        B(const B&) = default; // exception specification is "noexcept(true)"
        B(B&&, int = (throw Y(), 0)) noexcept;
        ~B() throw(Y);
    };
    int n = 7;
    struct D : public A, public B {
        int * p = new (std::nothrow) int[n];
        // D has the following implicitly-declared members:
        // D::D() throw(X, std::bad_array_new_length);
        // D::D(const D&) noexcept(true);
        // D::D(D&&) throw(Y);
        // D::~D() throw(X, Y);
    };

(since C++17)

### Example

Run this code

    #include <iostream>
    #include <exception>
    #include <cstdlib>

    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()
    }

    int main() {
      std::set_unexpected([]{
          std::cout << "That was unexpected" << std::endl; // flush needed
          std::abort();
      });
      f();
    }

Output:

    That was unexpected

### See also

- `noexcept` specifier

Retrieved from "https://en.cppreference.com/mwiki/index.php?title=cpp/language/except_spec&oldid=107814"