我正在和一位同事争论使用的危险catch(...)
他向我指出了一个可能的用途,严格暗示anycatch(...)
后面跟着一个跟踪/日志:以帮助确定一些非托管异常的起源。
我个人对此持怀疑态度。你知道任何明确的安全使用catch(...)
编辑:对于那些对辩论感兴趣的人,我的同事刚刚在 Programmers 网站上向我指出了这个问题。
我正在和一位同事争论使用的危险catch(...)
他向我指出了一个可能的用途,严格暗示anycatch(...)
后面跟着一个跟踪/日志:以帮助确定一些非托管异常的起源。
我个人对此持怀疑态度。你知道任何明确的安全使用catch(...)
编辑:对于那些对辩论感兴趣的人,我的同事刚刚在 Programmers 网站上向我指出了这个问题。
catch(...)
我所知道的最清晰有趣的安全使用是将用于处理各种异常的代码卸载到共享函数:
void handle_error() {
try {
throw;
} catch (TiresomelyPedanticException &) {
# lah lah I don't care
return;
} catch (InterestingException &) {
log_something();
throw;
}
// etc. This catch chain may *or may not* need a catch(...)
// of its own, it depends whether part of its job is to
// deal with the "miscellaneous" case.
}
您使用这样的功能:
try {
blah();
} catch(...) {
handle_error();
}
... 别的地方 ...
try {
something_that_throws_the_same_exceptions_as_blah();
} catch (...) {
handle_error();
}
不过,上面的模式可能有点像 C++03 主义。在 C++11 中,编写捕获 lambda 非常容易,以下内容可能对调用者更有用,并且catch(...)
模式中没有:
template <typename Func>
auto do_and_handle_error(Func f) -> decltype(f()) {
try {
return f();
} // catch chain goes here
}
像这样使用它:
do_and_handle_error(blah);
blah
或者在接受参数时实际上是必要的:
do_and_handle_error([&](void) { return blah(arg1,arg2); });
一个无聊的用法catch(...)
是保证在程序终止之前堆栈将被展开:
int my_main() {
RAIIClass some_object_i_want_to_get_destroyed_no_matter_what;
some_code_that_might_throw();
return 0;
}
int main() {
try {
return my_main();
} catch (...) {
throw;
}
}
如果没有捕获,标准将使其未指定或实现定义,some_object
如果代码抛出,是否被销毁。
异常经常被过度使用。这种过度使用几乎总是伴随着包罗万象的陈述。这通常是对异常的错误使用和理解的标志。我从不推荐它。可悲的是,在我工作的某个(坏)地方,其他人执行了这项政策。
以下始终是安全的:
try
{
some_local_stuff();
}
catch (...)
{
clean_up_local_stuff();
throw;
}
换句话说,catch-allcatch
块只能与重新抛出完全相同的异常或存储异常指针以传输异常结合使用。
使异常完全消失的 Catch 块应该具体说明它们处理的异常类型。