Namespaces
Variants
Views
Actions

dynamic exception specification

From cppreference.com
< cpp‎ | language

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

Contents

[edit] Syntax

throw(typeid, typeid, ...) (deprecated)

[edit] 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 fp, and pointer to member function mfp has a set of potential exceptions, which consists of types that might be thrown and possibly the "any" placeholder for the possibility of an exception of arbitrary type. This set is defined as follows:

1) If the declaration of f, fp, or mfp uses throw()(deprecated) or noexcept, the set is empty.
2) Otherwise, if the declaration of f, fp, or mfp uses a dynamic exception specification(deprecated), the set consists of the types listed in that specification
6) Otherwise, the set consists of the placeholder "any"

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, defined as follows:

1) If e is a core constant expression, the set is empty
2) Otherwise, the set 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. For all other function call expressions (where the name is not provided), the set consists of the placeholder "any"
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 "any" 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 apprlied 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 "any"
struct A { A(); };    // "new A"'s set is "any"
struct B { B() noexcept; }; // "B()"'s set is empty
struct D() { D() throw (double); }; // new D's set is "double, any"

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

  • If the set of potential exceptions contains "any", 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)
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)) throw(Y) 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)

[edit] 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()
}


[edit] See also