1

这是代码:

#include <iostream>

void f() {
    throw 1;
    std::cout << "f(): should not be printed!!\n";
    std::cout << "f(): not should this!!\n";
}

int main(int, const char**) {
    f();
    std::cout << "main(): This not be printed!!\n";
    return 0;
}

当作为控制台应用程序运行时,在调试模式下和调试器下没有堆栈展开并且 cout 语句被打印?

4

2 回答 2

4

如果您使用调试器运行,这在技术上是可行的。不过,你并没有讲述整个故事。抛出异常时,调试器将首先显示一个对话框。它看起来与此类似(我的是 Windows 8 上的 VS2012):

在此处输入图像描述

如果单击 Break 按钮,则调试器将在 throw 语句处中断,让您有机会检查状态。当您单击“继续”按钮时,异常将被忽略,程序将继续执行,就好像什么都没发生一样。当您休息然后恢复运行时也会发生这种情况。

这是一项功能,而不是错误,它允许您挽救已经花费大量时间的调试会话。继续下去当然不是很有用,因为您的程序可能处于不良状态,但替代方案也不是很好。您几乎总是希望单击 Break 并使用调试器来更正状态,以便您可以有意义地继续调试。

当然,如果没有调试器,这将永远不会发生,您的程序将立即终止。

堆栈展开的唯一可能方法是编写一个捕获异常的catch子句。不管你是否在调试。

于 2013-03-02T01:22:54.413 回答
1

回答我自己的问题的关键在于回答另一个子问题:在抛出异常之后,堆栈展开从什么时候开始?堆栈展开意味着以相反的顺序调用仍然存在的所有自动对象的析构函数。答:此时控制权被传递给异常处理程序,即异常被捕获。如果未捕获到异常,C++ 异常机制将调用终止函数,并且默认情况下调用 abort()。通过以下代码可以看到这种机制的作用:

struct X {
    ~X() { std::cout << "~X !!\n"; }
};

int main(int, const char**) {
    X x; 
    throw 1;
    return 0;
}

在 throw 之后,X 的析构函数永远不会被调用,因为无异常处理程序已获得控制权,因此程序中止。回到最初的问题,在调试调试版本和程序执行过程中,当周围没有合适的 try-catch 块时抛出异常,MS Studio 调试器在抛出点中断并呈现您会看到上面显示的对话窗口,并为您提供“继续”选项。Continue 不应被解释为“继续使用异常机制”,而是“继续进行,就好像什么都没发生一样”,即在 throw 之后使用下一行代码。

于 2013-03-02T22:51:50.020 回答