此代码:
#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)
答案 0 :(得分:14)
一次只能评估一个例外。从15.1 / 7
如果异常处理机制在完成对要抛出的表达式的评估之后但在捕获异常之前调用了一个通过异常退出的函数,则调用std :: terminate。
在您的示例中,std::terminate()
未被调用,因为实际上只抛出了一个异常。到达throw throw_it();
时,首先计算throw_it()
,这会导致函数在实际抛出之前被调用。由于该函数抛出异常并且永远不会返回原始的throw
,因此永远不会到达。如果throw_it()
没有抛出异常并返回一个整数值,那么将执行调用throw表达式。因此,对于您的示例,foo
保证会被打印。
但是从主动处理程序中抛出一个新异常呢?捕获异常时,它已被完全评估。当你抛出一个新的异常(而不是用“throw;”重新抛出)时,原始的异常就会被销毁,并且会开始评估新的异常。
从15.1 / 4
异常对象在异常的最后剩余活动处理程序通过除了重新抛出之外的任何方式退出之后被销毁.......
这满足了一次只能评估一个异常的规则。
答案 1 :(得分:3)
更具体地说,在进程中抛出异常 在定义的行为中抛出异常结果?
只要它不是在构造异常对象之后和捕获它之前就可以了,因为那时会调用std::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)