C++ 例外情况可以是“例外”吗;“复制”;通过异常指针?
对于一些多线程代码,我希望捕获所有异常并将它们传递给单个异常处理线程。以下是消息传递框架:C++ 例外情况可以是“例外”吗;“复制”;通过异常指针?,c++,exception-handling,c++11,C++,Exception Handling,C++11,对于一些多线程代码,我希望捕获所有异常并将它们传递给单个异常处理线程。以下是消息传递框架: #include <exception> struct message { virtual ~message() = default; virtual void act() = 0; }; struct exception_message : message { std::exception_ptr ep; virtual void act() {
#include <exception>
struct message
{
virtual ~message() = default;
virtual void act() = 0;
};
struct exception_message : message
{
std::exception_ptr ep;
virtual void act()
{
std::rethrow_exception(ep);
}
// ...
};
处理程序线程遍历其所有消息和调用act()
,并且它可以安装自己的try/catch块来处理所有发布的异常
现在我想知道如果我把这个消息的副本发送给多个接收者会发生什么。一般来说,消息可能有任意数量的接收者,因此我不想对异常消息设置任意限制。exception\u ptr
被记录为“共享所有权”智能指针,并且rethrow\u exception
不会引入数据竞争
所以我的问题是:通过将活动异常存储在
异常ptr
中、复制指针并多次调用rethrow\u exception
来复制活动异常是否合法?根据我对标准的理解,这是合法的。然而,我要注意的是,rethrow不会复制异常,因此,如果您同时修改共享异常对象并从其他线程访问它,则会将其提交给数据竞赛。如果异常是只读的(一旦抛出),那么您不应该有任何问题
关于储存期限:
15.1引发异常[除外.throw]
4除3.7.4.1所述外,异常对象的内存分配方式未指定。如果处理程序通过重试退出,则将控制权传递给同一异常的另一个处理程序。异常对象在异常的最后一个剩余活动处理程序通过除重试以外的任何方式退出后被销毁,或者引用异常对象的最后一个std::exception_ptr
(18.8.5)类型的对象被销毁
销毁,以较晚者为准。在前一种情况下,当处理程序退出时,销毁发生在处理程序中异常声明中声明的对象(如果有)销毁之后。在后一种情况下,销毁发生在std::exception_ptr
的析构函数返回之前
关于数据竞赛:
18.8.5异常传播[传播]
7为了确定是否存在数据竞争,对异常ptr
对象的操作只能访问和修改异常ptr
对象本身,而不能访问和修改它们引用的异常。在引用同一异常对象的exception\u ptr
对象上使用rethrow\u exception
不应引入数据竞争。[注意:如果rethrown\u exception
rethrows相同的异常对象(而不是副本),对该rethrown异常对象的并发访问可能会引入数据竞争。引用特定异常的exception\u ptr
对象数量的更改不会引入数据竞争
比赛-结束语]
关于重新播放:
[[noreturn]]void rethrow\u异常(异常\u ptr p)代码>
9要求:p
不应为空指针
10抛出:p引用的异常对象
谷歌刚刚发现:“在线程之间传输异常”从未尝试过类似的事情。将异常复制/通信到另一个线程并重新引发它听起来有点奇怪,因为一旦接收到异常,它就失去了所有上下文。原始线程,除了它自身包含的内容。检查一个线程中的信号异常,并记录它或其他什么,我可以理解。@ PioTrNycz:那个页面不是C++。在C++中没有<代码> STD::C++ C++,“KerrkSB:实际上是代码>”STD::“CopyOfferExers/Cuth>”意思是“代码> STD::MaxuExabutyPPTR <代码>标准C++。但是copy\u exception
是C++11早期草稿中关于make\u exception\u ptr
的名称。我也读过,但它是什么意思?是否多次抛出实际的同一异常对象?可以吗?这有什么意义吗?@KerrekSB:抛出的是什么意思throw
只是线程上下文中的一个goto/jump,它恰好与堆栈展开有关。因此,rethrow
几次完全相同的对象是没有问题的,对象本身可以被视为引导跳转(朝向右侧的catch
子句)。@KerrekSB-我刚刚做了同样的练习,我不认为有任何东西可以说明同一个exception\u ptr
对象的多个副本是否会抛出底层异常的不同副本。“ifrethrow_exception
rethrow同一个异常对象(而不是副本)…”的含义是允许任何一个。实际上,我认为这并不重要;通过引用捕获异常并修改其内容是非常奇怪的,这几乎是根据是否复制异常而导致不同行为的唯一方式。我同意,但这里有两个独立的问题:第一,对current_exception
的两个调用是否获取指向不同对象的指针;第二,是否rethrow\u exception
复制异常对象。在这两种情况下,我认为答案都是未指明的。皮特是正确的<允许使用代码>重新抛出\u异常
,但不要求抛出异常的副本。安腾ABI目前不提供复制异常的功能。一些供应商遵循此ABI,包括gcc/Linux和Apple。IIRC,微软确实在rethrow\u exception
上复制了一份,但我不太确定后一种说法。无论如何,这两种方法都是一致的。
try
{
// ...
}
catch (...)
{
exception_message em { std::current_exception(); }
handler_thread.post_message(em);
}