这是代码:
#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语句被打印出来了吗?
答案 0 :(得分:4)
如果使用调试器运行,这在技术上是可行的。但你并没有讲完整个故事。抛出异常时,调试器将首先显示一个对话框。它看起来与此类似(我的是Windows 8上的VS2012):
如果单击Break按钮,则调试器将在throw语句处中断,使您有机会检查状态。单击“继续”按钮,然后忽略该异常,程序将继续,就好像什么也没发生一样。当你休息然后恢复跑步时也会发生这种情况。
这是一个功能,而不是一个错误,它允许您挽救已花费大量时间的调试会话。由于您的程序可能处于不良状态,但替代方案也不是很好,因此继续通常不会有用。您几乎总是希望单击Break并使用调试器来纠正状态,以便您可以有意义地继续调试。
当然,如果没有调试器,这将永远不会发生,您的程序将立即终止。
堆栈展开的唯一可能方法是编写一个捕获异常的 catch 子句。无论您是否正在调试。
答案 1 :(得分:0)
回答我自己的问题的关键在于回答另一个子问题:在抛出异常之后,堆栈展开的时间点开始了吗?堆栈展开是指以相反顺序调用仍然存在的所有自动对象的析构函数。答案:在控件传递给异常处理程序时,即捕获异常。如果没有捕获到异常,则C ++异常机制要求调用terminate函数,默认情况下调用abort()。可以通过以下代码看到此机制:
struct X {
~X() { std::cout << "~X !!\n"; }
};
int main(int, const char**) {
X x;
throw 1;
return 0;
}
抛出之后,永远不会调用X的析构函数,因为无异常处理程序已获得控制权,因此程序将中止。 回到最初的问题,在你调试调试版本的时候和程序执行期间,如果周围没有合适的try-catch块,就会引发异常,MS Studio调试器在抛出点处中断并呈现您使用上面显示的对话窗口,并为您提供“继续”选项。继续被解释为不是“继续使用异常机制”,而是“随身携带,好像什么也没发生”,即抛出后的下一行代码。