可以通过异常指针"复制"异常吗?

Ker*_* SB 13 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()
    {
        std::rethrow_exception(ep);
    }

    // ...
};
Run Code Online (Sandbox Code Playgroud)

这是用例:

try
{
    // ...
}
catch (...)
{
    exception_message em { std::current_exception(); }
    handler_thread.post_message(em);
}
Run Code Online (Sandbox Code Playgroud)

处理程序线程遍历其所有消息和调用act(),并且它可以安装自己的try/catch块来处理所有已发布的异常.

现在我想知道如果我将此消息发送到多个接收器会发生什么.通常,消息可能有任意数量的收件人,因此我不想对异常传播消息设置任意限制.它exception_ptr被记录为"共享所有权"智能指针,并且rethrow_exception"不引入数据竞争".

所以我的问题是:通过将活动异常存储exception_ptr,复制指针和rethrow_exception多次调用来复制活动异常是否合法?

Mat*_* M. 5

根据我对标准的理解,它是合法的.但是我会注意到重新抛出不会复制异常,因此如果您修改它并从其他线程同时访问它,则共享异常对象本身将被提交给数据竞争.如果异常是只读的(一旦抛出),那么你应该没有任何问题.

关于存储时间:

15.1抛出异常[except.throw]

4除非在3.7.4.1中指出,否则异常对象的内存以未指定的方式分配.如果处理程序通过重新抛出退出,则控制将传递给另一个处理程序以获取相同的异常.异常对象在异常的最后剩余活动处理程序以除重新抛出之外的任何方式退出之后被销毁,或者std::exception_ptr引用异常对象的类型(18.8.5)的最后一个对象被销毁,以较晚者为准.在前一种情况下,当处理程序退出时,在销毁处理程序中的异常声明中声明的对象(如果有)之后立即发生销毁.在后一种情况下,破坏发生在std::exception_ptr返回的析构函数之前.

关于数据竞赛:

18.8.5异常传播[传播]

7为了确定是否存在数据争用,exception_ptr对象的操作只能访问和修改exception_ptr对象本身,而不是它们所引用的例外.使用引用同一异常对象的rethrow_exceptionon exception_ptr对象不应引入数据争用.[注意:如果rethrow_exception重新抛出相同的异常对象(而不是副本),对该重新抛出的异常对象的并发访问可能会引入数据争用.exception_ptr引用特定异常的对象数量的变化不会引入数据争用. - 尾注]

关于rethrow:

[[noreturn]] void rethrow_exception(exception_ptr p);

9要求:p不应为空指针.

10抛出:p指向的异常对象.

  • 皮特是对的.允许使用`rethrow_exception`但不需要抛出异常的副本.此时,Itanium ABI无法复制异常.一些供应商遵循这个ABI,包括gcc/Linux和Apple.IIRC,微软确实在`rethrow_exception`上复制了一份,但我对后一种说法不太确定.无论如何,这两种方法都是一致的. (6认同)
  • 我同意,但这里有两个不同的问题:首先,两个对`current_exception`的调用是否会获得引用不同对象的指针; 第二,`rethrow_exception`是否复制了异常对象.在这两种情况下,我认为答案是它没有具体说明. (2认同)