与std :: current_exception关联的数据的生命周期 [英] Lifetime of data associated with std::current_exception

查看:212
本文介绍了与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 of std::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 does
  • ex is initialized to reference a copy of the exception pointed to by eptr
  • 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 of exception_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆