与std :: current_exception关联的数据的生命周期 [英] Lifetime of data associated with std::current_exception
问题描述
考虑以下代码:
std::exception_ptr eptr{ std::current_exception() };
const char* msg = 0;
try {
if (eptr != std::exception_ptr{}) {
std::rethrow_exception(eptr);
}
} catch(const std::exception& ex) {
msg = ex.what();
}
我可以使用 msg
在捕获
之外?换句话说, ex
是否引用与 eptr
相同的异常实例?谢谢!
Can I use msg
outside of catch
? In other words does ex
references to the same exception instance as eptr
? Thanks!
推荐答案
TL; DR :我不会,因为 ex
和 eptr
(可能吗?)引用了不同的异常。 (请参阅编辑:可以保证,但是标准不够清晰,以至于我会避免依赖它)
TL;DR: I would not, because ex
and eptr
(might ?) reference different exceptions. (see edit: it might be guaranteed, but the standard is unclear enough that I would avoid relying on it)
异常的寿命由§15.1决定[except.throw] ,特别是:
The lifetime of exceptions is ruled by §15.1 [except.throw], and specifically:
4 /例外对象的内存分配方式未指定,除非有第3.7.4.1节中所述。如果处理程序通过重新抛出而退出,则针对相同异常的控制权将传递给另一个处理程序。 在最后一个剩余的活动异常处理程序退出后,异常对象被销毁了,而不是通过重新抛出,或者最后一个类型为
std :: exception_ptr
( §18.8.5)引用异常对象的对象将被销毁,以较晚的日期为准。在前一种情况下,销毁发生在处理程序退出后,即在 exception中声明的对象销毁后,处理程序中的声明(如果有)。在后一种情况下,销毁发生在std :: exception_ptr
的析构函数返回之前。然后,该实现可以为异常对象取消分配内存。任何此类重新分配均以未指定的方式完成。 [注意:引发的异常不会传播到其他线程,除非使用适当的库函数捕获,存储和重新抛出该异常;否则,异常不会传播到其他线程。参见§18.8.5和§30.6。 -尾注]
4/ The memory for the exception object is allocated in an unspecified way, except as noted in §3.7.4.1. If a handler exits by rethrowing, control is passed to another handler for the same exception. The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type
std::exception_ptr
(§18.8.5) that refers to the exception object is destroyed, whichever is later. In the former case, the destruction occurs when the handler exits, immediately after the destruction of the object declared in the exception-declaration in the handler, if any. In the latter case, the destruction occurs before the destructor ofstd::exception_ptr
returns. The implementation may then deallocate the memory for the exception object; any such deallocation is done in an unspecified way. [ Note: a thrown exception does not propagate to other threads unless caught, stored, and rethrown using appropriate library functions; see §18.8.5 and §30.6. —end note ]
但是,您还需要考虑上一段:
However, you also need to take into account the previous paragraph:
3 /抛出异常,将初始化一个临时对象(第8.5节,第12.8节),该异常称为异常对象。临时变量是一个左值,用于初始化在匹配处理程序(第15.3节)中命名的变量。 [...]
3/ Throwing an exception copy-initializes (§8.5, §12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable named in the matching handler (§15.3). [...]
因此,您的情况是什么:
Thus, what happens in your case:
-
eptr
初始化为指向当前正在运行的异常,从而保证该异常的寿命至少与它一样长 -
ex
初始化为引用副本 所指向的副本 c> - 当catch子句结束时,副本死亡
-
msg
指向副本,因此悬而未决...除非副本和原件在封面下共享相同的消息。
eptr
is initialized to point to the current exception in flight, guaranteeing this exception lives at least as long as it doesex
is initialized to reference a copy of the exception pointed to byeptr
- when the catch clause ends, the copy dies
msg
was pointing into the copy, and thus is left dangling... unless both copy and original shared the same message under the covers.
唯一可以确保异常有效期很长的方法是直接创建 std :: exception_ptr
。
The only way to guarantee that an exception lives long enough for your purpose is to create a std::exception_ptr
, directly.
编辑 Ralph Tandetzky鼓舞了我注意§18.8.5[传播] 说:
EDIT Ralph Tandetzky brough to my attention that §18.8.5 [propagation] says:
7 / [...] [注意:如果
rethrow_exception
重新抛出相同的异常对象(而不是副本),同时访问该重新抛出的异常对象可能会导致数据争用。引用特定异常的exception_ptr
对象的数量更改不会引入数据
竞争。 -尾注]
7/ [...] [ Note: if
rethrow_exception
rethrows the same exception object (rather than a copy), concurrent access to that rethrown exception object may introduce a data race. Changes in the number ofexception_ptr
objects that refer to a particular exception do not introduce a data race. —end note ]
在以下段落中建议:
[[noreturn]] void rethrow_exception(exception_ptr p);
9 / 要求: p
不能为空指针。
9/ Requires: p
shall not be a null pointer.
10 / 抛出: p <的异常对象/ code>引用。
10/ Throws: the exception object to which p
refers.
Throws 子句不应解释为某种 throw * p;
,但是可以具有与 throw;
相同的行为(重新-抛出完全相同的实例,而不是副本)。但是,由于在第7段中有一个 if ,看来它也可能是副本...
the Throws clause should not be interpreted as some kind of throw *p;
, but instead could have the same behavior as throw;
(re-throwing the very same instance, not a copy). However, since there is a if in paragraph 7, it seems it might be a copy too...
注意:有趣的实验表明基础对象可以共享。 。这与我对标准的阅读相矛盾;我不太了解 copy-initializes 的解释方式。
Note: interestingly experiments suggests that the underlying object may be shared... which contradicts my reading of the standard; I don't quite understand how copy-initializes could be interpreted differently though.
这篇关于与std :: current_exception关联的数据的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!