为什么代码会崩溃?

时间:2009-08-26 09:44:17

标签: c++ exception

在互联网上查找C ++脑筋急转弯,我找到了这个例子:

#include <iostream>

using namespace std;

class A {
public:
    A()
    {
        cout << "A::A()" << endl;
    }

    ~A()
    {
        cout << "A::~A()" << endl;
        throw "A::exception";
    }
};

class B {
public:
    B()
    {
        cout << "B::B()" << endl;
        throw "B::exception"; // <- crashes here
    }

    ~B()
    {
        cout << "B::~B()";
    }
};

int main(int, char**) {
    try
    {
        cout << "Entering try...catch block" << endl;

        A   objectA;
        B   objectB;

        cout << "Exiting try...catch block" << endl;
    }
    catch (const char* ex)
    {
        cout << ex << endl;
    }

    return 0;
}

这就是我认为该计划会做的事情:

  1. 当调用objectA的构造函数时,A :: A()将输出到屏幕。对象A构造成功。
  2. 当调用objectB的构造函数时,B :: B()将输出到屏幕。
  3. B的构造函数然后抛出异常。对象B未成功构建。
  4. 由于构造函数从未成功完成,因此未调用objectB的析构函数。
  5. 当退出try块时,对象超出范围时,将调用objectA的析构函数。
  6. 然而,当我运行该程序时,它实际上在标有&lt; - 的行处崩溃了。有人可以解释那时究竟发生了什么吗?

6 个答案:

答案 0 :(得分:11)

如果你真的在编码,不仅仅是脑力激荡永远不会从析构函数中抛出异常。如果在堆栈展开期间抛出异常,则调用terminate()。在你的情况下,在处理B的构造函数中抛出的异常时抛出了A的析构函数。

编辑: 更准确(如评论中所示) - 永远不要让异常逃避析构函数。析构函数中捕获的异常没有问题。但是如果在堆栈展开程序中必须处理两个异常 - 导致堆栈展开的异常和在展开期间转义析构函数的异常,std::terminate()就会出现。

答案 1 :(得分:6)

B::B()抛出异常堆栈时,展开开始。调用A::~A()并抛出另一个未在A::~A()内捕获的异常。

如果正在进行堆栈展开时另一个异常会离开析构函数,则会调用terminate()并且看起来像程序崩溃。

答案 2 :(得分:4)

C ++中的黄金法则 - 析构函数不应该抛出异常。忽略此规则将导致各种情况下的未定义行为。

答案 3 :(得分:3)

代码崩溃,因为B的C'tor抛出一个异常,然后启动“Stack Unwinding”程序:所有本地对象都被破坏,dus,A的D'tor被调用,并在Stack展开期间抛出异常,然后调用“abort”,因为同时不能有两个例外......

结论:

永远不要从D'tor中抛出异常,因为你可能会在Stack Unwinding期间扔掉它。

答案 4 :(得分:2)

退出try块时会调用

A::~A(),正是因为该对象超出了范围。这就是RAII工作的原因---它取决于被调用的析构函数,而不管为什么退出作用域。

A::~A()然后抛出异常。由于B::B()的异常仍被抛出堆栈,这会导致程序崩溃。

答案 5 :(得分:2)

你应该从不在析构函数中抛出异常。看看this question为什么。