This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


596. Replacing an exception object

Section: _N4606_.15.5.2  [except.unexpected]     Status: NAD     Submitter: Alisdair Meredith     Date: 12 September 2006

When a function throws an exception that is not in its exception-specification, std::unexpected() is called. According to _N4606_.15.5.2 [except.unexpected] paragraph 2,

If [std::unexpected()] throws or rethrows an exception that the exception-specification does not allow then the following happens: If the exception-specification does not include the class std::bad_exception (17.9.4 [bad.exception]) then the function std::terminate() is called, otherwise the thrown exception is replaced by an implementation-defined object of the type std::bad_exception, and the search for another handler will continue at the call of the function whose exception-specification was violated.

The “replaced by” wording is imprecise and undefined. For example, does this mean that the destructor is called for the existing exception object, or is it simply abandoned? Is the replacement in situ, so that a pointer to the existing exception object will now point to the std::bad_exception object?

Mike Miller: The call to std::unexpected() is not described as analogous to invoking a handler, but if it were, that would resolve this question; it is clearly specified what happens to the previous exception object when a new exception is thrown from a handler (14.2 [except.throw] paragraph 4).

This approach would also clarify other questions that have been raised regarding the requirements for stack unwinding. For example, 14.6.2 [except.terminate] paragraph 2 says that

In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate() is called.

This requirement could be viewed as in conflict with the statement in _N4606_.15.5.2 [except.unexpected] paragraph 1 that

If a function with an exception-specification throws an exception that is not listed in the exception-specification, the function std::unexpected() is called (_N4606_.D.6 [exception.unexpected]) immediately after completing the stack unwinding for the former function.

If it is implementation-defined whether stack unwinding occurs before calling std::terminate() and std::unexpected() is called only after doing stack unwinding, does that mean that it is implementation-defined whether std::unexpected() is called if there is ultimately no handler found?

Again, if invoking std::unexpected() were viewed as essentially invoking a handler, the answer to this would be clear, because unwinding occurs before invoking a handler.

Rationale (February, 2017):

The issue is moot after the adoption of document P0003.