8

这段代码:

#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;
  }
}

运行时打印foo,但可以保证这样做吗?更具体地说,在抛出异常的过程中抛出异常会导致定义的行为吗?这种行为是否会引发最近抛出的异常(就像上面的测试代码一样)?

供参考:

$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
4

2 回答 2

15

一次只能评估一个异常。从 15.1/7

如果异常处理机制在完成对要抛出的表达式的求值之后但在捕获异常之前调用通过异常退出的函数,则调用 std::terminate。

在您的示例std::terminate()中没有调用,因为实际上只抛出了一个异常。当throw throw_it();达到时,throw_it()首先评估导致在实际抛出异常之前调用函数。由于该函数抛出异常并且永远不会返回,throw因此永远不会到达原始函数。如果throw_it()没有抛出异常并返回一个整数值,则调用 throw 表达式将被执行。因此,对于您的示例foo,保证会被打印出来。

但是从活动处理程序中抛出一个新异常呢?当捕获到异常时,它已被完全评估。当您抛出一个新异常(而不是用“throw;”重新抛出)时,原始异常被破坏并开始评估新异常。

从 15.1/4

在异常的最后一个剩余活动处理程序以除重新抛出之外的任何方式退出后,异常对象被销毁或......

这满足了一次只能评估一个异常的规则。

于 2013-05-29T02:00:45.003 回答
3

更具体地说,在抛出异常的过程中抛出异常会导致定义的行为吗?

只要不是在构造异常对象之后并在捕获它之前就可以了,因为 thenstd::terminate会被调用。在您的示例中,根本没有创建异常对象,因此没有任何东西要抛出,而是range_error("foo")被抛出。这是要捕获的异常。

你可以这样检查:

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;
    }
}

输出:

not good!

RUN SUCCESSFUL (total time: 59ms)
于 2013-05-29T02:07:26.587 回答