Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can exceptions be "duplicated" via exception pointers?

For some multithreaded code, I would like to capture all exceptions and pass a them to a single exception handling thread. Here's the message passing framework:

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

    // ...
};

Here's the use case:

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

The handler thread goes through all its messages and calls act(), and it can install its own try/catch block to handle all the posted exceptions.

Now I was wondering what happens if I send copies this message to multiple receivers. In general, mes­sa­ges may have any number of recipients, and so I don't want to put arbitrary restrictions on exception pro­pa­ga­tion messages. The exception_ptr is documented as a "shared-ownership" smart pointer, and rethrow_exception "does not introduce a data race".

So my question: Is it legitimate to duplicate an active exception by storing it in an exception_ptr, copy­ing the pointer, and calling rethrow_exception multiple times?

like image 357
Kerrek SB Avatar asked Oct 02 '12 12:10

Kerrek SB


People also ask

Does C++ throw new Exception?

C++ Standard Exceptions An exception and parent class of all the standard C++ exceptions. This can be thrown by new. This can be thrown by dynamic_cast. This is useful device to handle unexpected exceptions in a C++ program.

What are exceptions C++?

Exception handling is a mechanism that separates code that detects and handles exceptional circumstances from the rest of your program. Note that an exceptional circumstance is not necessarily an error.

How do you throw a custom exception in C++?

In the main() function, a try-catch block is created to throw and handle the exception. Within the try block, an object of MyCustomException is created and thrown using the throw keyword. The exception is then caught in the catch block, where the message is printed by accessing the what() function.


1 Answers

From my understanding of the Standard, it is legitimate. However I would note that the rethrow does not duplicate the exception, and therefore the shared exception object itself is submitted to data races should you modify it and access it from other threads meantime. If the exception is read-only (once thrown), then you should not have any issue.

Regarding storage duration:

15.1 Throwing an exception [except.throw]

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.

Regarding data races:

18.8.5 Exception propagation [propagation]

7 For purposes of determining the presence of a data race, operations on exception_ptr objects shall access and modify only the exception_ptr objects themselves and not the exceptions they refer to. Use of rethrow_exception on exception_ptr objects that refer to the same exception object shall not introduce a data race. [ 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 ]

Regarding rethrow:

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

9 Requires: p shall not be a null pointer.

10 Throws: the exception object to which p refers.

like image 96
Matthieu M. Avatar answered Sep 22 '22 09:09

Matthieu M.