Throwing an exception transfers control to a handler. An object is passed and the type of that object determines which handlers can catch it. [ Example:
throw "Help!";
can be caught by a handler of const char* type:
try { // ... } catch(const char* p) { // handle character string exceptions here }
and
class Overflow { public: Overflow(char,double,double); }; void f(double x) { throw Overflow('+',x,3.45e107); }
can be caught by a handler for exceptions of type Overflow
try {
f(1.2);
} catch(Overflow& oo) {
// handle exceptions of type Overflow here
}
— end example ]
When an exception is thrown, control is transferred to the nearest handler with a matching type ([except.handle]); “nearest” means the handler for which the compound-statement or ctor-initializer following the try keyword was most recently entered by the thread of control and not yet exited.
A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively. The temporary is an lvalue and is used to initialize the variable named in the matching handler ([except.handle]). If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified) void the program is ill-formed. Except for these restrictions and the restrictions on type matching mentioned in [except.handle], the operand of throw is treated exactly as a function argument in a call ([expr.call]) or the operand of a return statement.
The memory for the exception object is allocated in an unspecified way, except as noted in [basic.stc.dynamic.allocation]. If a handler exits by rethrowing, control is passed to another handler for the same exception. The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr ([propagation]) that refers to the exception object is destroyed, whichever is later. In the former case, the destruction occurs when the handler exits, immediately after the destruction of the object declared in the exception-declaration in the handler, if any. In the latter case, the destruction occurs before the destructor of std::exception_ptr returns. The implementation may then deallocate the memory for the exception object; any such deallocation is done in an unspecified way. [ Note: an exception thrown by a throw-expression does not propagate to other threads unless caught, stored, and rethrown using appropriate library functions; see [propagation] and [futures]. — end note ]
When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided ([class.copy]).
An exception is considered caught when a handler for that exception becomes active ([except.handle]). [ Note: An exception can have active handlers and still be considered uncaught if it is rethrown. — end note ]
If the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught, calls a function that exits via an exception, std::terminate is called ([except.terminate]). [ Example:
struct C {
C() { }
C(const C&) { throw 0; }
};
int main() {
try {
throw C(); // calls std::terminate()
} catch(C) { }
}
— end example ]
A throw-expression with no operand rethrows the currently handled exception ([except.handle]). The exception is reactivated with the existing temporary; no new temporary exception object is created. The exception is no longer considered to be caught; therefore, the value of std::uncaught_exception() will again be true. [ Example: code that must be executed because of an exception yet cannot completely handle the exception can be written like this:
try { // ... } catch (...) { // catch all exceptions // respond (partially) to exception throw; // pass the exception to some // other handler }
— end example ]
If no exception is presently being handled, executing a throw-expression with no operand calls std::terminate() ([except.terminate]).