Подтвердить что ты не робот

Могут ли исключения быть "дублированы" с помощью указателей исключений?

Для некоторого многопоточного кода я хотел бы зафиксировать все исключения и передать их одному потоку обработки исключений. Здесь схема передачи сообщений:

#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);
    }

    // ...
};

Здесь используется прецедент:

try
{
    // ...
}
catch (...)
{
    exception_message em { std::current_exception(); }
    handler_thread.post_message(em);
}

Провод обработчика проходит через все его сообщения и вызовы act(), и он может установить свой собственный блок try/catch для обработки всех опубликованных исключений.

Теперь мне было интересно, что произойдет, если я отправлю копии этого сообщения нескольким получателям. В общем, mes & shy; sa & shy; ges может иметь любое количество получателей, и поэтому я не хочу устанавливать произвольные ограничения на исключения pro & shy; сообщения pa & shy; ga & shy; exception_ptr задокументирован как интеллектуальный указатель "совместного использования", а rethrow_exception "не вводит гонку данных".

Итак, мой вопрос: законно ли дублировать активное исключение, сохраняя его в exception_ptr, copy & shy, указав указатель и вызывая rethrow_exception несколько раз?

4b9b3361

Ответ 1

Из моего понимания Стандарта это законно. Однако я хотел бы отметить, что ретролл не дублирует исключение, и поэтому сам общий объект исключения отправляется на расы данных, если вы измените его и одновременно получите доступ к нему из других потоков. Если исключение доступно только для чтения (один раз бросается), то у вас не должно быть проблем.

Относительно продолжительности хранения:

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_exception on exception_ptr, относящихся к одному и тому же объекту исключения, не должно вводить гонку данных. [Примечание: если rethrow_exception возвращает один и тот же объект исключения (а не копию), одновременный доступ к этому повторному объекту исключения может привести к гонке данных. Изменения в количестве объектов exception_ptr, которые ссылаются на конкретное исключение, не вводят данные раса. -end note]

Относительно rethrow:

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

9 Требуется: p не должен быть нулевым указателем.

10 Throws: объект исключения, к которому относится p.