使用catch(...)(省略号)进行事后分析

SF.*_*SF. 14 c++ debugging exception-handling try-catch ellipsis

有人在不同的问题采用建议catch(...)通过整个周围的意外/不可预见的例外-捕获所有未处理的,否则main()try{}catch(...){}块.

这听起来像一个有趣的想法,可以节省大量时间调试程序,并至少留下一些发生的事情.

这个问题的本质是什么信息可以通过这种方式恢复(除了我留下的任何调试全局),以及如何恢复它(如何访问和识别被调用的任何catch)

此外,有什么警告与它有关.特别是:

  • 它会与后来发芽的线程一起玩吗?
  • 它不会破坏处理段错误(在别处作为信号捕获)
  • 它会不会影响其他try ... catch块不可避免地嵌套在里面,那是否有处理预期的异常?

Mar*_*ork 10

是的,这是个好主意.

如果你让异常转义为main,那么在实现定义的天气下,堆栈在应用程序关闭之前就会解开.所以在我看来,你必须抓住主要的所有例外情况.

那么问题就变成了如何处理它们.
某些操作系统(参见MS和SE)提供了一些额外的调试工具,因此在捕获异常之后重新抛出异常非常有用(因为无论如何堆栈已经解开).

int main()
{
    try
    {
        /// All real code
    }
    // I see little point in catching other exceptions at this point 
    // (apart from better logging maybe). If the exception could have been caught
    // and fixed you should have done it before here.

    catch(std::exception const& e)
    {
         // Log e.what() Slightly better error message than ...
         throw;
    }
    catch(...)   // Catch all exceptions. Force the stack to unwind correctly.
    {
        // You may want to log something it seems polite.
        throw;  // Re-throw the exception so OS gives you a debug opportunity.
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 它会与后来发芽的线程一起玩吗?

它应该对线程没有影响.通常,您必须手动加入任何子线程以确保它们已退出.当主要出口没有明确定义时,子线程会发生什么事情的确切细节(因此请阅读您的文档),但通常所有子线程都会立即死亡(一种令人讨厌且可怕的死亡,不涉及展开它们的堆栈).

如果您正在讨论子线程中的异常.同样,这个定义不明确(所以请阅读您的文档)但是如果一个线程通过异常退出(即由于异常而不是返回而用于启动线程的函数退出)那么这通常会导致应用程序终止(同样的影响)如上).因此,最好停止所有异常退出线程.

  • 它不会破坏处理段错误(在别处作为信号捕获)

信号不受异常处理机制的影响.
但是因为信号处理程序可能会在堆栈上放置一个奇怪的结构(因为它们自己的返回处理回到正常代码),所以从信号处理程序中抛出异常不是一个好主意,因为这可能会导致意外结果(并且绝对不可移植) ).

  • 它会不会影响其他try ... catch块不可避免地嵌套在里面,那是否有处理预期的异常?

应该对其他处理程序没有影响.


Mat*_*lia 5

据我所知,catch(...)在 Win32 上也会捕获 SEH 异常,而您不想这样做。如果您收到 SEH 异常,那是因为发生了非常可怕的事情(主要是访问冲突),因此您不能再信任您的环境。你能做的几乎所有事情都可能会因为另一个 SEH 异常而失败,所以它甚至不值得尝试。此外,一些 SEH 异常旨在被系统捕获;更多关于这个在这里

因此,我的建议是std::exception对所有异常使用基本异常类(例如),并在“catchall”中捕获该类型;您的代码无法准备好处理其他类型的异常,因为它们的定义是未知的。

  • catch(...) 在 Windows 下是否捕获 SEH 异常是特定于编译器的。对于 Microsoft 编译器,vc7 的 catch(...) 总是捕获 SEH 异常。对于 vc8 以后的版本,有一个编译器选项可以启用该行为 (`/EHa`),但默认情况下它是关闭的。 (3认同)