c++ - 在析构函数中处理异常(但不抛出)

标签 c++ exception destructor

我了解到,如果在堆栈展开期间抛出析构函数程序将会中止,因为那时会传播超过 1 个异常。

这是一个带有注释的示例:

class Foo
{
public:
    ~Foo()
    {
        ReleaseResources();
    }

private:
    int* pInt;

    void ReleaseResources()
    {
        if (!pInt)
            throw 0;
        else delete pInt;
    }
};

int main() try
{
    {
        Foo local;
        throw 1;
    } // aborting here, because now 2 exceptions are propagating!

    return 0;
}
catch (int& ex)
{
    return ex;
}

但是我有一个类层次结构,其中一个析构函数调用一个可能抛出异常的函数,并且由于该条目层次结构被毒化了,这意味着现在所有析构函数都被标记为 noexcept(false) .

虽然编译器可以插入异常代码,但对于这些类的用户来说是不行的,因为如果发生上述代码示例中的情况,它不会阻止程序中止。

因为我希望析构函数是异常安全的,所以我想到将它们全部标记为 noexcept但像这样处理析构函数中可能出现的异常:

相同的示例,但经过重新设计,无法中止,并且析构函数异常安全:

class Foo
{
public:
    ~Foo() noexcept
    {
        try
        {
            ReleaseResources();
        }
        catch (int&)
        {
            // handle exception here
            return;
        }
    }

private:
    int* pInt;

    void ReleaseResources()
    {
        if (!pInt)
            throw 0;
        else delete pInt;
    }
};

int main() try
{
    {
        Foo local;
        throw 1;
    } // OK, not aborting here...

    return 0;
}
catch (int& ex)
{
    return ex;
}

问题是,这是在 destrucotrs 中处理异常的正常方法吗?是否有任何可能使此设计出错的示例?

主要目标是拥有异常安全的析构函数。

还有一个附带问题,在第二个示例中,在堆栈展开期间仍有 2 个异常传播,为什么没有调用中止?如果在堆栈展开期间只允许一个异常?

最佳答案

The question is, is this normal approach to handle exceptions inside destrucotrs? are there any examples that could make this design go wrong?

是的,您可以避免像这样抛出析构函数如果您的//handle exception here 代码实际上处理了异常。但在实践中,如果您在销毁期间抛出异常,通常意味着没有好的方法来处理异常。

从析构函数中抛出意味着某种清理失败。也许资源泄露了,数据无法保存并且现在丢失了,或者某些内部状态无法设置或恢复。无论是什么原因,如果您可以避免或解决问题,您就不必首先抛出问题。

您对这种糟糕情况的解决方案(抛出析构函数)仅在您实际不处于糟糕情况时才有效。在实践中,如果您尝试应用它,您会发现没有什么可写的//handle exception here,除了可能警告用户或记录问题。


if only one exception is allowed during stack unwinding?

没有这样的规则。在堆栈展开期间抛出的问题是如果未捕获的异常从析构函数中逃逸。如果析构函数在内部抛出并捕获异常,则它不会影响正在进行的堆栈展开。 std::terminate 明确说明堆栈展开何时以终止结束(link):

In some situations exception handling must be abandoned for less subtle error handling techniques. These situations are:

[...]

-- when the destruction of an object during stack unwinding terminates by throwing an exception, or

[...]

关于c++ - 在析构函数中处理异常(但不抛出),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58596480/

相关文章:

c++ - 从工作线程调用主线程回调函数

c++ - 如何使用自定义注册系统注册 dll 并查看导入的 dll 的可执行文件的 PE?

oop - 我应该使用异常来检查构造函数中的无效参数吗?

php - 即使使用 catch block ,PDO 未捕获的 PDO 异常也会在连接错误时转储密码

c++ - 如何在具有指向对象的指针数组的类中创建复制构造函数和析构函数,其中对象本身具有指向 int 的指针数组

Python 文件对象、关闭和析构函数

c++ - 在 C++ 中确定成员的类实例

c++ - 输入您想要显示在数组中的数量

c++ - 删除非指针 vector 中的指针

c++ - 构建线程 boost 库