在析构函数中捕获异常

abe*_*nky 26 c++ destructor exception

是否有可能使析构函数捕获异常然后重新抛出它们?
如果是这样,我将如何做到这一点,因为try声明没有明确的地方?

基本上,我想理想地做:

CMyObject::~CMyObject()  
{
    catch(...)    // Catch without a try.  Possible?
    {
        LogSomeInfo();
        throw;  // re-throw the same exception
    }
    // Normal Destructor operations
}
Run Code Online (Sandbox Code Playgroud)

背景
我有一个庞大的,复杂的应用程序,在某处抛出未处理的异常.我没有轻松访问main或顶级消息泵或任何类似的东西,所以没有容易捕获所有未处理的异常的地方.

我认为任何未处理的异常必须通过一堆析构函数,因为堆栈是解开的.所以,我正在考虑catch在析构函数中散布一堆语句.然后,至少我会知道抛出异常时正在播放的对象.但我不知道这是否可行,或者是否可取.

Dan*_*rey 16

编辑:您可以std::uncaught_exception用来检查当前是否正在抛出异常(即,由于异常,堆栈展开是否正在进行).无法捕获该异常或以其他方式从析构函数中访问它.因此,如果您的日志记录不需要访问异常本身,则可以使用

CMyObject::~CMyObject()  
{
  if(std::uncaught_exception()) {
    LogSomeInfo(); // No access to exception.
  }
  // Normal Destructor operations
}
Run Code Online (Sandbox Code Playgroud)

请注意,这个问题是在2013年提出的,同时std::uncaught_exception被替换为std::uncaught_exceptions(注意最后的附加内容s)返回一个int.对于一个理由,见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4152.pdf,因此,如果您使用的是C++ 17,你应该更喜欢新的版本.上面的论文还解释了为什么旧的std::uncaught_exception在某些情况下不能按预期工作.


另一种选择可能是std::set_terminate.如果您希望在未捕获异常并且即将终止程序时调用该方法,这将非常有用.在终止处理程序中,我通常打印有关的例外,它在哪里,从我的日志文件中发起最后终止程序之前(demangled)回溯的一些信息.这是编译器和系统的具体,但一个真正的帮手,因为它节省了大量的,如果你写的服务器进程和经常的日志文件是你从OPS得到的时间.

  • 但删除中间的6行.你有一个*uncaught*异常,所以throw会调用`std :: terminate`.另外,`throw;`在catch块之外无效. (3认同)
  • @DanielFrey`notaught_exception`和`current_exception`在同一时刻是**永远不是真的.`uncaught_exception`在catch子句的开头变为false,在此之前`current_exception`为false.看看[这个答案](http://stackoverflow.com/a/28267655/200121)我的问题. (2认同)

Mat*_* M. 8

std::uncaught_exception()当且仅当正在处理异常时,您可以使用哪个返回true.因为C++ 98它一直可用,并且被替代由std::current_exception它返回一个std::exception_ptr.

但是,您必须小心不要在无人看守的上下文中抛出另一个异常,否则std::terminate将被捕获​​.例:

X::~X() {
    if (std::uncaught_exception()) {
        try {
            LogSomeInfo();
            // and do something else...
        } catch(...) {}
    }
}
Run Code Online (Sandbox Code Playgroud)


650*_*502 7

析构函数无法捕获导致实例销毁的异常.

您只能知道uncaught_exception在销毁期间是否存在任何"活动异常"(请参阅参考资料)(或者,在C++ 17中,它们中有多少个存在uncaught_exceptions)但是异常可能确实存在之后处理.

处理异常非常困难,比第一眼看上去更困难,原因是异常安全无法按构成进行扩展.在我看来,这意味着基本上不可能有非常琐碎的有状态子系统具有强大的异常安全性(如果异常被抛出则内部状态没有发生).这是很久以前发现的(参见1994年Tom Cargill的"异常处理:一种虚假的安全感")但显然仍然被大部分C++社区所忽视.

处理我能想到的异常的唯一合理方法是让子系统具有明确定义的接口和厚厚的"墙"(内部没有副作用可能会逃脱),并且可以从头开始重新初始化为一个众所周知的状态出现问题时需要.这不是微不足道的,但可以在合理的范围内正确地完成.

在所有其他情况下,捕获异常时系统的全局状态在捕获点最多是无限期的,并且在我看来很少有用例可以在这种情况下做任何事情,除非立即尽可能大声死亡而不是在不知道发生了什么的情况下采取进一步行动(死计划不说谎).在我看来,即使继续调用析构函数也有些疑问.

或者你可能尝试尽可能的功能,但这也不是一个简单的路径(至少对我的大脑来说),它也远离现实(大多数计算机是具有数十亿比特可变状态的可变对象:你可以假装情况并非如此,他们反而是数学函数,没有状态,可预测的输出取决于输入...但在我看来,你只是在欺骗自己).