在 C++ 中,我试图在一次捕获中捕获所有类型的异常(就像catch(Exception)
在 C# 中一样)。它是如何完成的?更重要的是,如何捕获被零除的异常?
9 回答
catch (...)
{
// Handle exceptions not covered.
}
重要注意事项:
- 更好的方法是捕获您实际上可以从中恢复的特定类型的异常,而不是所有可能的异常。
- catch(...) 还将捕获某些严重的系统级异常(取决于编译器),您将无法可靠地从中恢复。以这种方式捕捉它们然后吞下它们并继续可能会在您的程序中导致更严重的问题。
- 根据您的上下文,可以接受使用 catch(...),前提是重新抛出异常。在这种情况下,您记录所有有用的本地状态信息,然后重新抛出异常以允许它向上传播。但是,如果您选择这条路线,您应该阅读RAII 模式。
您不想使用 catch (...) (即带有省略号的 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,请使用析构函数创建您自己的类。
你可以用它catch(...)
来捕捉一切,但是你没有得到一个对象来检查、重新抛出、记录或做任何事情。所以......你可以“加倍” try 块并重新抛出一个处理单一类型的外部捕获。如果您为自定义异常类型定义构造函数,该类型可以从您想要组合在一起的所有类型构建自身,则此方法非常有效。然后,您可以从 中抛出一个默认构造的catch(...)
,其中可能包含一条消息或代码,例如“未知”,或者您想要跟踪此类事情。
例子:
try
{
try
{
// do something that can produce various exception types
}
catch( const CustomExceptionA &e ){ throw e; } \
catch( const CustomExceptionB &e ){ throw CustomExceptionA( e ); } \
catch( const std::exception &e ) { throw CustomExceptionA( e ); } \
catch( ... ) { throw CustomExceptionA(); } \
}
catch( const CustomExceptionA &e )
{
// Handle any exception as CustomExceptionA
}
如果我没记错的话(自从我看过 C++ 以来已经有一段时间了),我认为以下应该可以解决问题
try
{
// some code
}
catch(...)
{
// catch anything
}
和一个快速的谷歌(http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html)似乎证明我是正确的。