c++ 如何在一个catch块中捕获所有类型的异常?

vawmfj5a  于 2023-03-14  发布在  其他
关注(0)|答案(9)|浏览(190)

在C++中,我试图在一次捕获中捕获所有类型的异常(就像C#中的catch(Exception))。这是如何做到的?还有,如何捕获被零除的异常?

omjgkv6w

omjgkv6w1#

当然,你可以使用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,请使用析构函数创建自己的类。

u4dcyp6a

u4dcyp6a2#

您可以使用catch(...)捕获所有内容,但是您无法获得对象来检查、重新抛出、记录,或者用做任何事情。所以...你可以把try块“加倍”,然后重新抛出到一个处理单个类型的外部catch中。如果你为一个自定义异常类型定义了构造函数,这个构造函数可以从你想组合在一起的所有类型中构建自己,那么这是非常理想的。然后,您可以抛出一个从catch(...)构造的默认值,其中可能包含消息或代码,如“UNKNOWN”,或者您希望跟踪此类内容的任何方式。
示例:

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
}
qij5mzcb

qij5mzcb3#

如果我没记错的话(我已经有一段时间没看过C++了),我认为下面的代码应该可以解决这个问题

try
{
 // some code
}
catch(...)
{
 // catch anything
}

而一个快速的谷歌(http://www.oreillynet.com/pub/a/network/2003/05/05/cpluspocketref.html)似乎证明了我是正确的。

0g0grzrc

0g0grzrc4#

catch (...)
{
   // Handle exceptions not covered.
}

重要考虑因素:

  • 一种更好的方法是捕获可以实际恢复的特定类型的异常,而不是捕获所有可能的异常。
  • catch(...)还将捕获某些严重的系统级异常(因编译器而异),您将无法可靠地从中恢复。以这种方式捕获这些异常,然后将其吞入并继续可能会导致程序中出现更严重的问题。
  • 根据您的上下文,使用catch(...)是可以接受的,前提是异常被重新引发。在这种情况下,您记录所有有用的本地状态信息,然后重新引发异常以允许它向上传播。但是,如果您选择此路由,则应仔细阅读RAII pattern
ldxq2e6h

ldxq2e6h5#

想使用catch (...)(即用省略号捕获),除非你真的、肯定的、最可证明的需要它。
这是因为有些编译器(最常见的是Visual C++ 6)也会将诸如分段错误等错误和其他非常糟糕的情况转化为异常,您可以使用catch (...)轻松处理这些异常。这非常糟糕,因为您再也看不到崩溃了。
从技术上讲,是的,你也可以捕捉除以零(你必须“StackOverflow”),但你真的应该避免在第一时间进行这样的除法。
相反,请执行以下操作:

  • 如果您实际上知道预期的异常类型,那么只捕获这些类型,而不捕获其他类型,并且
  • 如果您需要自己抛出异常,并且需要捕获所有将要抛出的异常,那么让这些异常派生自std::exception(正如Adam Pierce建议的那样)并捕获它。
dauxcl2d

dauxcl2d6#

如果你在windows上,需要处理像被零除和访问冲突这样的错误,你可以使用一个结构化异常转换器,然后在你的转换器中抛出一个c++异常:

void myTranslator(unsigned code, EXCEPTION_POINTERS*)
{
    throw std::exception(<appropriate string here>);
}

_set_se_translator(myTranslator);

注意,代码会告诉你错误是什么。另外,你需要使用/EHa选项(C/C++ -〉代码生成器-〉启用C/C++异常= Yes with SEH Exceptions)进行编译。
如果没有意义,请 checkout [_set_se_translator](http://msdn.microsoft.com/en-us/library/5z4bw5h5(VS.80).aspx)))的文档

7kqas0il

7kqas0il7#

如果捕获所有异常(包括操作系统异常)确实是您所需要的,那么您需要查看一下您的编译器和操作系统。例如,在Windows上,您可能使用“__try”关键字或编译器开关来使“try/catch”捕获SEH异常,或者两者兼而有之。

ljsrvy3e

ljsrvy3e8#

让你所有的自定义异常类都继承自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!";
    }
};
fnx2tebb

fnx2tebb9#

在C++中,标准没有定义被零除的异常,并且实现往往不会抛出它们。

相关问题