Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Throwing an exception while throwing an exception

This code:

#include <iostream>
#include <stdexcept>

using namespace std;

int throw_it() {
  throw range_error( "foo" );
}

int main() {
  try {
    throw throw_it();
  }
  catch ( exception const &e ) {
    cerr << e.what() << endl;
    return 0;
  }
}

prints foo when run, but is it guaranteed to do so? More specifically, does throwing an exception while in the process of throwing an exception result in defined behavior? And is that behavior to throw the most-recently-thrown exception (as the test code above does)?

FYI:

$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
like image 641
Paul J. Lucas Avatar asked May 29 '13 01:05

Paul J. Lucas


2 Answers

Only one exception can be evaluated at a time. From 15.1/7

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.

In your example std::terminate() is not called because only one exception is actually being thrown. When throw throw_it(); is reached, throw_it() is evaluated first which results in the function being called before the exception is actually thrown. Since the function throws an exception and never returns the original throw is never reached. If throw_it() did not throw an exception and returned an integer value the calling throw expression would then be executed. So for your example foo is guaranteed to be printed.

But what about throwing a new exception from within an active handler? When an exception is caught it has been fully evaluated. When you throw a new exception (rather than rethrowing with "throw;") the original exception is destroyed and evaluation of the new exception begins.

From 15.1/4

The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing or....

This satisfies the rule that only one exception can be evaluated at a time.

like image 172
Captain Obvlious Avatar answered Oct 09 '22 03:10

Captain Obvlious


More specifically, does throwing an exception while in the process of throwing an exception result in defined behavior?

it is OK as long as it is not after constructing an exception object and before catching it, because then std::terminate would be called. In your example exception object is not created at all, so there is nothing to be thrown, instead range_error("foo") is thrown. This is exception to be catched.

You can inspect this this way:

int throw_it() {
    throw range_error( "foo" );
    return 19;
}

int main() {
    try {
        try { // nested try is perfectly legal
            throw throw_it();
        } catch (...) {
            cerr << "not good!";
        }
    } catch (exception const &e) {
        cerr << e.what() << endl;
        return 0;
    }
}

output:

not good!

RUN SUCCESSFUL (total time: 59ms)
like image 31
4pie0 Avatar answered Oct 09 '22 03:10

4pie0