【发布时间】:2010-09-08 12:34:49
【问题描述】:
在 C++ 中,我试图一次捕获所有类型的异常(例如 C# 中的 catch(Exception))。它是如何完成的?更重要的是,如何捕获被零除的异常?
【问题讨论】:
标签: c++ exception-handling try-catch
在 C++ 中,我试图一次捕获所有类型的异常(例如 C# 中的 catch(Exception))。它是如何完成的?更重要的是,如何捕获被零除的异常?
【问题讨论】:
标签: c++ exception-handling try-catch
您可以使用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
}
【讨论】:
您不想要使用 catch (...)(即带有省略号的 catch),除非您确实、肯定、最可证明的需要它。
原因是一些编译器(最常见的是 Visual C++ 6)也会将诸如分段错误和其他非常糟糕的情况之类的错误转换为您可以使用 catch (...) 轻松处理的异常。这很糟糕,因为您再也看不到崩溃了。
从技术上讲,是的,您也可以捕获除以零(为此您必须使用“StackOverflow”),但您确实应该首先避免进行此类除法。
相反,请执行以下操作:
【讨论】:
当然,您可以使用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 (...)
{
// Handle exceptions not covered.
}
重要注意事项:
【讨论】:
如果您在 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 异常,或两者兼而有之。
【讨论】:
在 C++ 中,标准没有定义被零除异常,实现往往不会抛出它们。
【讨论】:
如果我没记错的话(我已经有一段时间没有看过 C++了),我认为下面的方法应该可以解决问题
try
{
// some code
}
catch(...)
{
// catch anything
}
而且快速谷歌 (http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html) 似乎证明我是正确的。
【讨论】:
让你所有的自定义异常类都继承自 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!";
}
};
【讨论】: