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

问题描述 投票:1回答: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;
}

问题是,这是处理内部构造异常的正常方法吗?有没有可能使该设计出错的示例?

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

还有一个附带的问题,在第二个示例中,在堆栈展开期间,仍然有2个异常正在传播,怎么不调用abort?如果在堆栈展开期间仅允许一个异常?

c++ exception destructor
1个回答
0
投票
~Foo() noexcept

noexcept在这种情况下是多余的,因为没有子对象具有可能抛出的析构函数。如果没有

,则析构函数将隐式为noexcept

问题是,这是处理构造体内部异常的正常方法吗?

Try-catch通常是在析构函数内部还是其他方式处理异常的方式。

但是,在这种情况下更好的解决方案是:

void ReleaseResources()
{
    delete pInt;
}

没有必要扔在这里,不这样做会更简单。

还有一个附带的问题,在第二个示例中,在堆栈展开期间,仍然有2个异常正在传播,怎么不调用abort?

因为允许。


0
投票

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

从析构函数中抛出意味着某种清理失败。也许资源泄漏,数据无法保存,现在丢失或某些内部状态无法设置或还原。不管是什么原因,如果您可以避免或解决问题,都不必首先考虑。因此,仅当您实际上没有遇到这种情况时,您对这种情况(抛出析构函数)的解决方案才有效。


如果在堆栈展开期间仅允许一个例外?

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

在某些情况下,必须放弃异常处理,以减少不太细微的错误处理技术。这些情况是:

[...]

-当堆栈展开期间对象的销毁通过引发异常终止时,或

[...]

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.