C++ Programming Guide

Managing Flow of Control

In C++, exception handlers do not correct the exception and then return to the point at which the exception occurred. Instead, when an exception is generated, control is passed out of the block that threw the exception, out of the try block that anticipated the exception, and into the catch block whose exception declaration matches the exception thrown.

The catch block handles the exception. It might rethrow the same exception, throw another exception, jump to a label, return from the function, or end normally. If a catch block ends normally, without a throw, the flow of control passes over all other catch blocks associated with the try block.

Whenever an exception is thrown and caught, and control is returned outside of the function that threw the exception, stack unwinding takes place. During stack unwinding, any automatic objects that were created within the scope of the block that was exited are safely destroyed via calls to their destructors.

If a try block ends without an exception, all associated catch blocks are ignored.


Note -

An exception handler cannot return control to the source of the error by using the return statement. A return issued in this context returns from the function containing the catch block.


Branching Into and Out of try Blocks and Handlers

Branching out of a try block or a handler is allowed. Branching into a catch block is not allowed, however, because that is equivalent to jumping past an initiation of the exception.

Nesting of Exceptions

Nesting of exceptions, that is, throwing an exception while another remains unhandled, is allowed only in restricted circumstances. From the point when an exception is thrown to the point when the matching catch clause is entered, the exception is unhandled. Functions that are called along the way, such as destructors of automatic objects being destroyed, may throw new exceptions, as long as the exception does not escape the function. If a function exits via an exception while another exception remains unhandled, the terminate() function is called immediately.

Once an exception handler has been entered, the exception is considered handled, and exceptions may be thrown again.

You can determine whether any exception has been thrown and is currently unhandled. See "Calling the uncaught_exception() Function".

Specifying Exceptions to Be Thrown

A function declaration can include an exception specification, a list of exceptions that a function may throw, directly or indirectly.

The two following declarations indicate to the caller that the function f1 generates only exceptions that can be caught by a handler of type X, and that the function f2 generates only exceptions that can be caught by handlers of type W, Y, or Z:


void f1(int) throw(X);
void f2(int) throw(W,Y,Z);

A variation on the previous example is:


void f3(int) throw(); // empty parentheses

This declaration guarantees that no exception is generated by the function f3. If a function exits via any exception that is not allowed by an exception specification, it results in a call to the predefined function unexpected(). By default, unexpected() calls abort() to exit the program. You can change this default behavior by calling the set_unexpected() function. See "set_unexpected() ".

The check for unexpected exceptions is done at program execution time, not at compile time. Even if it appears that a disallowed exception might be thrown, there is no error unless the disallowed exception is actually thrown at runtime.

The compiler can, however, eliminate unnecessary checking in some simple cases. For instance, no checking for f is generated in the following example.


void foo(int) throw(x);
void f(int) throw(x);
{
	foo(13);
}

The absence of an exception specification allows any exception to be thrown.