如何在一个 catch 块中捕获所有类型的异常?
-
09-06-2019 - |
题
在 C++ 中,我试图在一次捕获中捕获所有类型的异常(例如 catch(Exception)
在 C# 中)。它是如何完成的?更重要的是,如何捕获被零除的异常?
解决方案
catch (...)
{
// Handle exceptions not covered.
}
重要考虑因素:
- 更好的方法是捕获实际上可以从中恢复的特定类型的异常,而不是捕获所有可能的异常。
- catch(...) 还会捕获某些严重的系统级异常(取决于编译器),您将无法可靠地从中恢复。以这种方式捕获它们然后吞下它们并继续可能会导致您的程序出现更严重的问题。
- 根据您的上下文,使用 catch(...) 是可以接受的,前提是重新抛出异常。在这种情况下,您记录所有有用的本地状态信息,然后重新抛出异常以允许其向上传播。但是,您应该阅读 RAII模式 如果你选择这条路线。
其他提示
你 不 想要使用 catch (...) (即抓住省略号)除非你真的、绝对、最有可能需要它。
原因是某些编译器(最常见的是 Visual C++ 6)也会将分段错误和其他非常糟糕的条件等错误转换为异常,您可以使用 catch (...) 轻松处理这些异常。这非常糟糕,因为您再也看不到崩溃了。
从技术上讲,是的,您也可以捕获除以零(您必须为此“StackOverflow”),但您确实应该首先避免进行此类除法。
相反,请执行以下操作:
- 如果您确实知道会发生什么样的异常,请捕获这些类型,不要再捕获更多类型,并且
- 如果您需要自己抛出异常,并且需要捕获您将抛出的所有异常,请使这些异常派生自 std::exception (如 Adam Pierce 建议的那样)并捕获它。
如果您在 Windows 上并且需要处理除零和访问冲突等错误,您可以使用结构化异常转换器。然后在你的翻译器中你可以抛出一个 C++ 异常:
void myTranslator(unsigned code, EXCEPTION_POINTERS*)
{
throw std::exception(<appropriate string here>);
}
_set_se_translator(myTranslator);
请注意,代码会告诉您错误是什么。此外,您还需要使用 /EHa 选项进行编译(C/C++ -> Code Generatrion -> Enable C/C++ Exceptions = Yes with SEH Exceptions)。
如果这没有意义,请查看 [_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)
如果捕获所有异常(包括操作系统异常)确实是您所需要的,那么您需要查看您的编译器和操作系统。例如,在 Windows 上,您可能有“__try”关键字或编译器开关来使“try/catch”捕获 SEH 异常,或两者兼而有之。
让所有自定义异常类继承自 std::exception,然后您可以简单地捕获 std::exception。这是一些示例代码:
class WidgetError
: public std::exception
{
public:
WidgetError()
{ }
virtual ~WidgetError() throw()
{ }
virtual const char *what() const throw()
{
return "You got you a widget error!";
}
};
在 C++ 中,标准没有定义被零除异常,并且实现往往不会抛出它们。
当然,您可以使用 catch (...) { /* code here */ }
, ,但这实际上取决于您想做什么。在 C++ 中,你有确定性析构函数(没有那种终结垃圾),所以如果你想清理,正确的做法是使用 RAII。
例如。代替:
void myfunc()
{
void* h = get_handle_that_must_be_released();
try { random_func(h); }
catch (...) { release_object(h); throw; }
release_object(h);
}
做类似的事情:
#include<boost/shared_ptr.hpp>
void my_func()
{
boost::shared_ptr<void> h(get_handle_that_must_be_released(), release_object);
random_func(h.get());
}
如果您不使用 boost,请使用析构函数创建您自己的类。
如果我没记错的话(自从我看过 C++ 以来已经有一段时间了),我认为以下应该可以解决问题
try
{
// some code
}
catch(...)
{
// catch anything
}
和快速谷歌(http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html)似乎证明我是正确的。