问题描述
从析构函数抛出异常的主要问题是,在调用析构函数的那一刻,另一个异常可能是飞行中"(std::uncaught_exception() == true
),所以它是在这种情况下该怎么做并不明显.用新的覆盖"旧的例外将是处理这种情况的可能方法之一.但决定在这种情况下必须调用 std::terminate
(或另一个 std::terminate_handler
).
The main problem with throwing exceptions from destructor is that in the moment when destructor is called another exception may be "in flight" (std::uncaught_exception() == true
) and so it is not obvious what to do in that case. "Overwriting" the old exception with the new one would be the one of the possible ways to handle this situation. But it was decided that std::terminate
(or another std::terminate_handler
) must be called in such cases.
C++11 通过 std::nested_exception
类引入了嵌套异常功能.此功能可用于解决上述问题.旧的(未捕获的)异常可以嵌套到新的异常中(反之亦然?),然后可以抛出嵌套的异常.但是这个想法没有被使用.std::terminate
在 C++11 和 C++14 中仍然会在这种情况下被调用.
C++11 introduced nested exceptions feature via std::nested_exception
class. This feature could be used to solve the problem described above. The old (uncaught) exception could be just nested into the new exception (or vice versa?) and then that nested exception could be thrown. But this idea was not used. std::terminate
is still called in such situation in C++11 and C++14.
所以问题.是否考虑了嵌套异常的想法?它有什么问题吗?C++17不会改变这种情况吗?
So the questions. Was the idea with nested exceptions considered? Are there any problems with it? Isn't the situation going to be changed in the C++17?
推荐答案
当您的析构函数作为堆栈展开过程的一部分执行时(当您的对象不是作为堆栈展开的一部分创建时),您引用的问题就会发生1,并且您的析构函数需要发出异常.
The problem you cite happens when your destructor is being executed as part of the stack unwinding process (when your object was not created as part of stack unwinding)1, and your destructor needs to emit an exception.
那么它是如何工作的呢?你有两个例外.异常 X
是导致堆栈展开的异常.异常 Y
是析构函数想要抛出的异常.nested_exception
只能容纳一个.
So how does that work? You have two exceptions in play. Exception X
is the one that's causing the stack to unwind. Exception Y
is the one that the destructor wants to throw. nested_exception
can only hold one of them.
所以也许你有异常 Y
contain 一个 nested_exception
(或者可能只是一个 exception_ptr
).那么...你如何在 catch
站点处理这个问题?
So maybe you have exception Y
contain a nested_exception
(or maybe just an exception_ptr
). So... how do you deal with that at the catch
site?
如果你捕捉到Y
,并且它恰好有一些嵌入的X
,你怎么得到它?记住:exception_ptr
是类型擦除;除了传递它之外,你唯一能做的就是重新扔掉它.所以人们应该这样做吗:
If you catch Y
, and it happens to have some embedded X
, how do you get it? Remember: exception_ptr
is type-erased; aside from passing it around, the only thing you can do with it is rethrow it. So should people be doing this:
catch(Y &e)
{
if(e.has_nested())
{
try
{
e.rethrow_nested();
}
catch(X &e2)
{
}
}
}
我没有看到很多人这样做.尤其是因为可能存在大量的 X
-es.
I don't see a lot of people doing that. Especially since there would be an exceedingly large number of possible X
-es.
1:请不要使用 std::uncaught_exception() == true
来检测这种情况.这是非常有缺陷的.
1: Please do not use std::uncaught_exception() == true
to detect this case. It is extremely flawed.
这篇关于为什么 C++ 不使用 std::nested_exception 来允许从析构函数抛出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!