所以在 C++ 中嵌套异常的方法std::nested_exception
是:
void foo() {
try {
// code that might throw
std::ifstream file("nonexistent.file");
file.exceptions(std::ios_base::failbit);
}
catch(...) {
std::throw_with_nested(std::runtime_error("foo failed"));
}
}
但是这种技术在希望嵌套异常的每个级别都使用显式的 try/catch 块,这至少可以说是丑陋的。
RAII,Jon Kalb 将其扩展为“责任获取就是初始化”,是一种处理异常的更简洁的方法,而不是使用显式的 try/catch 块。使用 RAII,显式 try/catch 块在很大程度上仅用于最终处理异常,例如为了向用户显示错误消息。
查看上面的代码,在我看来,进入foo()
可以被视为需要报告任何异常std::runtime_error("foo failed")
并将详细信息嵌套在嵌套异常中的责任。如果我们可以使用 RAII 来承担这个责任,那么代码看起来会更干净:
void foo() {
Throw_with_nested on_error("foo failed");
// code that might throw
std::ifstream file("nonexistent.file");
file.exceptions(std::ios_base::failbit);
}
有没有办法在这里使用 RAII 语法来替换显式的 try/catch 块?
为此,我们需要一种类型,当调用其析构函数时,检查析构函数调用是否是由于异常,如果是则嵌套该异常,并抛出新的嵌套异常,以便正常展开。这可能看起来像:
struct Throw_with_nested {
const char *msg;
Throw_with_nested(const char *error_message) : msg(error_message) {}
~Throw_with_nested() {
if (std::uncaught_exception()) {
std::throw_with_nested(std::runtime_error(msg));
}
}
};
但是std::throw_with_nested()
,需要“当前处理的异常”处于活动状态,这意味着它除了在 catch 块的上下文中之外不起作用。所以我们需要类似的东西:
~Throw_with_nested() {
if (std::uncaught_exception()) {
try {
rethrow_uncaught_exception();
}
catch(...) {
std::throw_with_nested(std::runtime_error(msg));
}
}
}
不幸的是,据我所知,rethrow_uncaught_excpetion()
在 C++ 中没有任何定义。