从析构函数中抛出异常

格雷格·罗杰斯(Greg Rogers)

大多数人说,永远不要从析构函数中抛出异常-这样做会导致未定义的行为。Stroustrup指出:“向量析构函数显式地为每个元素调用析构函数。这意味着,如果抛出一个元素析构函数,则向量破坏会失败...实际上,没有很好的方法来防止从析构函数抛出的异常,因此库如果元素析构函数抛出异常,则不做任何保证”(摘自附录E3.2)

本文似乎另有说法-抛出析构函数或多或少是可以的。

所以我的问题是-如果从析构函数中抛出导致未定义的行为,您如何处理析构函数期间发生的错误?

如果清理操作期间发生错误,您是否忽略它?如果这是一个错误,可以在堆栈中处理,但不能在析构函数中正确处理,那么将异常抛出到析构函数之外是否有意义?

显然,这类错误很少见,但可能出现。

马丁·约克

从析构函数中抛出异常是危险的。
如果已经传播了另一个异常,则应用程序将终止。

#include <iostream>

class Bad
{
    public:
        // Added the noexcept(false) so the code keeps its original meaning.
        // Post C++11 destructors are by default `noexcept(true)` and
        // this will (by default) call terminate if an exception is
        // escapes the destructor.
        //
        // But this example is designed to show that terminate is called
        // if two exceptions are propagating at the same time.
        ~Bad() noexcept(false)
        {
            throw 1;
        }
};
class Bad2
{
    public:
        ~Bad2()
        {
            throw 1;
        }
};


int main(int argc, char* argv[])
{
    try
    {
        Bad   bad;
    }
    catch(...)
    {
        std::cout << "Print This\n";
    }

    try
    {
        if (argc > 3)
        {
            Bad   bad; // This destructor will throw an exception that escapes (see above)
            throw 2;   // But having two exceptions propagating at the
                       // same time causes terminate to be called.
        }
        else
        {
            Bad2  bad; // The exception in this destructor will
                       // cause terminate to be called.
        }
    }
    catch(...)
    {
        std::cout << "Never print this\n";
    }

}

基本上可以归结为:

任何危险的事情(即可能引发异常的事情)都应通过公共方法(不一定直接)进行。然后,您的类的用户可以通过使用公共方法并捕获任何潜在的异常来潜在地处理这些情况。

然后,析构函数将通过调用这些方法(如果用户未明确这样做)来结束对象,但是会捕获和丢弃所有抛出的异常(尝试解决问题之后)。

因此,实际上您将责任转移给了用户。如果用户能够纠正异常,他们将手动调用适当的功能并处理任何错误。如果对象的用户不担心(因为对象将被销毁),则析构函数将留给企业处理。

一个例子:

std :: fstream

close()方法可能会引发异常。如果文件已打开,则析构函数调用close(),但要确保任何异常都不会传播到析构函数之外。

因此,如果文件对象的用户想要对关闭文件相关的问题进行特殊处理,他们将手动调用close()并处理任何异常。另一方面,如果他们不在乎,则将使用析构函数来处理这种情况。

斯科特·迈尔斯(Scott Myers)在他的著作《有效的C ++》中有一篇关于该主题的出色文章。

编辑:

显然也在“更有效的C ++”
项目11中:防止异常离开析构函数

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

std :: vector中的元素可能具有抛出的析构函数吗?

非虚拟析构函数c ++的异常

从析构函数中抛出异常对于vtable是安全的吗?

noexcept函数返回具有抛出析构函数的类

如何从成员析构函数中捕获异常

.NET中的析构函数

析构函数中的c ++异常

在析构函数中引发异常时,为什么不调用重载的删除?

在析构函数方法中引发异常

如何在C ++异常类析构函数中释放变量

处理析构函数内部的异常(但不抛出)

如何检测构造函数是否为带有抛出析构函数的异常

抛出未处理的异常后过早离开的析构函数是否可以释放成员数据?

为什么我无法处理从析构函数外部抛出的异常?

构造函数中引发了异常:调用了析构函数吗?

析构函数中的析构函数?

为什么您不能从析构函数中抛出。例子

std :: thread在vc ++中的析构函数中获取中止异常

使用=重载函数时析构函数中的异常

在派生类构造函数中引发异常。为什么调用基类析构函数而不是派生类析构函数?

C ++中的析构函数直接调用

析构函数引发异常

捕获在析构函数中引发的异常的块

为什么C ++不使用std :: nested_exception允许从析构函数中抛出?

C ++,静态对象构造函数中的异常会绕过先前静态对象的析构函数

析构函数抛出System.NullReferenceException

抛出析构函数导致内存泄漏

Python 中的析构函数

抛出数据成员的析构函数