gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 19:58:05 27 4
gpt4 key购买 nike

我读到过,由于堆栈展开,从析构函数中抛出不是一个好主意。我不确定我是否完全理解。所以我尝试了下面的例子

struct foo
{
~foo()
{
throw 1;
}
};


struct bar
{
~bar()
{
throw 2;
}
};

int main()
{
try
{
foo a;
bar b;
throw 3;
}catch(int a)
{
std::cout << a;
}
}

现在我期望 a 将是 1,因为首先抛出 3,然后调用 b 的析构函数,抛出 2,然后调用 a 的析构函数,抛出 1。显然情况并非如此,这可以解释为什么它从析构函数中抛出不是一个好主意。我的问题是为什么 abort() 被称为 b 的析构函数?

最佳答案

堆栈展开期间抛出异常这将导致调用std::terminate,其默认操作是调用std::abort.

CERT在他们的 ERR33-CPP. Destructors must not throw exceptions 中有很好的解释文件说(强调我的):

A destructor is very likely to be called during stack unwinding resulting from an exception being thrown. If the destructor itself throws an exception, having been called as the result of an exception being thrown, then the function std::terminate() is called with the default effect of calling std::abort(). This could provide the opportunity for a denial-of-service attack. Hence, destructors must satisfy the no-throw guarantee, that is, they must not throw an exception if they themselves have been called as the result of an exception being thrown.

C++ 标准草案 15.2 构造函数和析构函数 中对此进行了介绍,其中指出:

The process of calling destructors for automatic objects constructed on the path from a try block to a throw-expression is called “stack unwinding.” If a destructor called during stack unwinding exits with an exception, std::terminate is called (15.5.1). [ Note: So destructors should generally catch exceptions and not let them propagate out of the destructor. —end note ]

请注意,在 C++11 中,析构函数被隐式指定 noexcept(true),只要它调用的函数都不允许异常。因此,在这种情况下,无论从析构函数中抛出什么,都会调用 std::terminate

来自 12.4 析构函数部分:

A declaration of a destructor that does not have an exception-specification is implicitly considered to have the same exception-specification as an implicit declaration (15.4).

15.4 说:

An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f’s implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions.

理论上你可以使用 std::uncaught_exception在析构函数中但在 GotW #47 中检测堆栈展开 Herb Sutter 解释了为什么这种技术不像看起来那么有用。

尽管 Herb 最近在 N4152: uncaught_exceptions 中提出了一个修复方案

关于c++ - 为什么不能从析构函数中抛出。例子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26395476/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com