C++单个对象析构函数抛出异常

3

我试图理解为什么从析构函数中抛出异常会导致程序崩溃。我发现很多例子都是两个对象同时抛出多个异常,编译器无法处理多个异常,但在我的情况下,只有一个异常从析构函数中抛出。为什么我的程序仍然崩溃?

class MyClass {
private:
    string name;
public:
    MyClass (string s) :name(s) {
        cout << "constructor " << name << endl;
    }
    ~MyClass() {
        cout << "Destroying " << name << endl;
        throw "invalid";
    }
};
int main( ) 
{ 
    try {
        MyClass mainObj("M");
    }
    catch (const char *e) {
        cout << "exception: " << e << endl;
        cout << "Mission impossible!\n";
    }   
    catch (...) {
        cout << "exception: " <<  endl;
    }
    return 0; 
}

为什么不发布完整的代码?你从哪里学到了删除必要的包含指令等等?这非常不好:通常(虽然在这种情况下不是)错误是由于缺少包含而引起的。请不要这样做。请发布完整的代码。 - Cheers and hth. - Alf
可能是Exception in Destructor C++的重复问题。 - Korni
@Korni:那里的一个答案(当前选择的“解决方案”)也回答了这个问题,但那个问题是关于嵌套异常的。 - Cheers and hth. - Alf
2个回答

6

来自MingW g++编译器的解释:

[P:\temp]
> g++ foo.cpp
foo.cpp: 在析构函数 'MyClass::~MyClass()' 中:
foo.cpp:14:15: 警告: throw将总是调用terminate() [-Wterminate]
         throw "invalid";
               ^~~~~~~~~
foo.cpp:14:15: 注:在C++11中,析构函数默认为noexcept

如果您真的想让它抛出,可以这样做:

~MyClass() noexcept(false){

太遗憾了,MingW的错误信息并不完全正确。如果正在进行堆栈展开(即如果析构函数由于另一个异常被抛出但尚未被捕获而被调用),则从析构函数中抛出异常会导致调用terminate()。如果没有进行堆栈展开,则从析构函数中抛出异常不会(必然)导致调用terminate() - 但会引起其他问题。 - Peter
@Peter:您的观点适用于C++03。在C++11及以后的版本中,根据C++11 §15.4/9:“每当抛出异常并且寻找处理程序(15.3)遇到一个具有不允许该异常的异常规范的函数的最外层块时,如果该异常规范是动态异常规范,则调用函数std::unexpected()(15.5.2),否则调用函数std::terminate()(15.5.1)。”当前标准为C++17。 - Cheers and hth. - Alf
@Cheersandhth.-Alf - 同意。尽管在C++17中,有人费力地从析构函数中抛出异常,可能也会确保该析构函数具有允许该操作的throw-spec.....(我意识到这种讨论可能会变得循环,但这就是我在先前评论中的想法)。 - Peter

2
自从C++11以来,析构函数被隐式声明为noexcept文档

非抛出函数是指所有其他函数(具有评估为true的noexcept说明符表达式以及析构函数、默认特殊成员函数和释放函数)

重点在于析构函数

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