catch(...)未捕获异常,我的程序仍然崩溃。

20

我的应用程序在初始化过程中崩溃,我遇到了一个测试人员的问题。我增加了更多的日志记录和异常处理,但它仍然会因为通用的“此程序已停止工作”消息而崩溃,而不是触发我的错误处理。

考虑到我的main()看起来像这样,并且在何种情况下会没有触发catch(...)

try{
    simed::CArmApp app(0, cmd);
    for(bool done = false;!done;) 
    {
        done = !app.frame();
    }
} catch(const std::runtime_error &e){
    handleApplicationError(e.what());
    return -1;
} catch(...) {
    handleApplicationError("Unknown Error");
    return -999;
}

我的代码调用了一个进行OpenGL渲染的库,我认为这就是出错的地方。


1
我不确定我理解了。你怎么知道它是一个未捕获的异常? - kec
因为 handleApplicationError 没有被调用(它会弹出一个消息框并关闭我的启动屏幕,但这两个都没有发生)。 - Mr. Boy
抱歉,我误解了。我的理解是catch(...)应该让我重新掌控,如果出现任何问题,或者说我想知道在什么情况下这不是真的。 - Mr. Boy
6
不行。在C++中,异常是一种非常具体的编程语言机制,不像硬件异常。您必须明确使用“throw”语句才能抛出异常。因此,例如,任何类型的未定义行为(如空指针引用等)通常都不会导致抛出C++异常。 - kec
我认为下面Monks的回答解决了这个问题。 - kec
显示剩余3条评论
5个回答

28

如果C++的catch(...)块没有捕获错误,则可能是由于Windows错误。

在Windows中,有一个称为Structured Exception Handling的概念,当发生诸如解引用无效指针、除以零等不良事件时,操作系统会引发“异常”。我说“异常”,因为这些不是C++异常。相反,这些是Windows以C语言方式定义的关键错误——这是因为Win32是用C编写的,所以C++异常不可行。

另请参见:

基于评论的更新

如果您想同时使用C++异常处理和SEH,可以尝试以下(未经测试)代码:

__try
{
    try
    {
        // Your code here...
    }
    catch (std::exception& e)
    {
        // C++ exception handling
    }
}
__except(HandleStructuredException())
{
    // SEH handling 
}

1
有趣,谢谢。我不确定如何同时实现它们 - 或者在我的示例代码中应该如何编写才更安全。我认为第三方库是问题出在哪里 - 该库确实会抛出C++异常,所以我希望他们能够为我解决这些问题!您是否可以使用我的代码作为示例来说明如何做到完美呢? - Mr. Boy
我已经添加了一些示例代码,也许这可以用来捕获两种类型的异常。 - Peter Monks
呃,(做这个)有点恶心,但看起来这就是解决方案。 - Mr. Boy
1
结构化异常处理(__try, __except, 和 __finally)和C++异常处理(trycatch)不能在同一个函数中使用。需要注意的是,处理结构化异常的情况非常罕见。 - James McNellis

8

如果在处理另一个异常的过程中,因为栈展开而销毁的对象的析构函数抛出了异常,程序将会退出,无论是否使用catch(...)


7
到目前为止,据我所知,catch(...)至少有两种情况无法真正地捕获异常:
  1. 超过1个未处理的异常:当一个异常在先前发生的异常被处理之前被引发时,C++无法处理它,应用程序将崩溃。
  2. 抛出不在异常规范列表中的异常:如果任何方法抛出一个不在异常规范列表中(在任何情况下)的异常,则会调用unexpected,该函数又会调用abort

+1,但在情况#1中,这不仅仅是一个“崩溃”,而是对std::terminate的调用。 - Angew is no longer proud of SO
@Angew,没错,实际上默认情况下terminate也会调用abort,所以和#2是一样的。 - Rakib
我想要特别明确的是,如果你的抛出函数被其他函数调用,或者其中任何一个函数被声明为“noexcept”,那么#2也包括在内。如果抛出函数被正确指定但是被一个“noexcept”函数调用,那么调用者将会终止。这可能很基础,但它刚刚让我费了几分钟的思考时间,所以! - underscore_d

1

你是否声明了任何全局对象? 如果你在主循环之外创建了任何对象,那可能就解释了为什么它没有被捕获(它不在你的try-catch中)。


它肯定是由于在try/catch块内部调用的某些东西而崩溃 - 我得到了日志来证明代码正在运行,然后它就死了,但我的所有错误处理都没有被触发 :( - Mr. Boy

0
如果你正在使用多线程,并且抛出了一个异常,触发了线程的析构函数,那么有可能会忽略该异常并调用abort函数。std::jthread(C++20)解决了这个问题,但如果你没有访问C++20的权限,那么在抛出异常之前,你需要有一个清理函数/lambda来终止线程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接