11 KiB
[except.handle]
14 Exception handling [except]
14.4 Handling an exception [except.handle]
Theexception-declaration in ahandler describes the type(s) of exceptions that can cause thathandler to be entered.
Theexception-declaration shall not denote an incomplete type, an abstract class type, or an rvalue reference type.
Theexception-declaration shall not denote a pointer or reference to an incomplete type, other than âpointer to cv voidâ.
A handler of typeâarray of Tâ orfunction type T is adjusted to be of type âpointer to Tâ.
Ahandler is a match for an exception object of typeE if
The handler is of type cv T orcv T& andE and T are the same type (ignoring the top-level cv-qualifiers), or
the handler is of type cv T orcv T& andT is an unambiguous public base class of E, or
the handler is of type cv T or const T& where T is a pointer or pointer-to-member type andE is a pointer or pointer-to-member type that can be converted to T by one or more of
a standard pointer conversion not involving conversions to pointers to private or protected or ambiguous classes
a qualification conversion, or
the handler is of type cv T or const T& where T is a pointer or pointer-to-member type and E is std::nullptr_t.
[Note 1:
Athrow-expression whose operand is an integer literal with value zero does not match a handler of pointer or pointer-to-member type.
A handler of reference to array or function type is never a match for any exception object ([expr.throw]).
â end note]
[Example 1: class Matherr { /* ... / virtual void vf(); };class Overflow: public Matherr { / ... / };class Underflow: public Matherr { / ... / };class Zerodivide: public Matherr { / ... */ };
void f() {try { g(); } catch (Overflow oo) {// ...} catch (Matherr mm) {// ...}}
Here, theOverflow handler will catch exceptions of typeOverflow and theMatherr handler will catch exceptions of typeMatherr and of all types publicly derived fromMatherr including exceptions of typeUnderflow andZerodivide.
â end example]
The handlers for a try block are tried in order of appearance.
[Note 2:
This makes it possible to write handlers that can never be executed, for example by placing a handler for a final derived class after a handler for a corresponding unambiguous public base class.
â end note]
A... in a handler'sexception-declaration specifies a match for any exception.
If present, a... handler shall be the last handler for its try block.
If no match is found among the handlers for a try block, the search for a matching handler continues in a dynamically surrounding try block of the same thread.
If the search for a handler exits the function body of a function with a non-throwing exception specification, the function std::terminate ([except.terminate]) is invoked.
[Note 3:
An implementation is not permitted to reject an expression merely because, when executed, it throws or might throw an exception from a function with a non-throwing exception specification.
â end note]
[Example 2: extern void f(); // potentially-throwingvoid g() noexcept { f(); // valid, even if f throwsthrow 42; // valid, effectively a call to std::terminate}
The call tof is well-formed despite the possibility for it to throw an exception.
â end example]
If no matching handler is found, the function std::terminate is invoked; whether or not the stack is unwound before this invocation ofstd::terminate is implementation-defined ([except.terminate]).
A handler is considered active when initialization is complete for the parameter (if any) of the catch clause.
[Note 4:
The stack will have been unwound at that point.
â end note]
Also, an implicit handler is considered active when the function std::terminate is entered due to a throw.
A handler is no longer considered active when the catch clause exits.
The exception with the most recently activated handler that is still active is called thecurrently handled exception.
Referring to any non-static member or base class of an object in the handler for afunction-try-block of a constructor or destructor for that object results in undefined behavior.
Exceptions thrown in destructors of objects with static storage duration or in constructors of objects associated with non-block variables with static storage duration are not caught by afunction-try-block on the main function.
Exceptions thrown in destructors of objects with thread storage duration or in constructors of objects associated with non-block variables with thread storage duration are not caught by afunction-try-block on the initial function of the thread.
If a return statement ([stmt.return]) appears in a handler of thefunction-try-block of a constructor, the program is ill-formed.
The currently handled exception is rethrown if control reaches the end of a handler of thefunction-try-block of a constructor or destructor.
Otherwise, flowing off the end of the compound-statement of a handler of a function-try-block is equivalent to flowing off the end of the compound-statement of that function (see [stmt.return]).
The variable declared by the exception-declaration, of typecv T or cv T&, is initialized from the exception object, of type E, as follows:
if T is a base class of E, the variable is copy-initialized ([dcl.init]) from an lvalue of type T designating the corresponding base class subobject of the exception object;
otherwise, the variable is copy-initialized ([dcl.init]) from an lvalue of type E designating the exception object.
The lifetime of the variable ends when the handler exits, after the destruction of any objects with automatic storage duration initialized within the handler.
When the handler declares an object, any changes to that object will not affect the exception object.
When the handler declares a reference to an object, any changes to the referenced object are changes to the exception object and will have effect should that object be rethrown.