Is it possible to check if a given exception_ptr instance has a specific type of exception?

Let's assume I have an instance std::exception_ptr

. I need to check if the main exception is of a certain type (and ideally access it). This can be done as follows:

std::exception_ptr p = ...;
try
{
    std::rethrow_exception(p);
}
catch(MyType const& x)
{
    ...
}
catch(...)
{
    // do smth else
}

      

Is there a better way?

Is there a guarantee that std::rethrow_exception

it is not going to copy a major exception causing problems like throwing std::bad_alloc

?

+3


source to share


1 answer


std::rethrow_exception

is the only way to drop the main exception object, so it must be used. Assuming each exception inherits from std::exception

, you can create a dynamic_cast if-else chain. I've tried this with dummy exceptions and it works. If it's better, it's a matter of taste. In this approach, it is easier to have some general context or do two cases or do something in the case of two types.

The more interesting part of your question was about copying an object - according to the C ++ reference std::exception_ptr

"is a generic pointer type", so copying shouldn't happen. Although, I made simple test cases and it is copied to Visual Studio 2017. It works fine in GCC. I have no information about other compilers.



#include <cstdio>
#include <string>
#include <exception>

class A :public std::exception
{
public: 
};


class B :public std::exception
{
public:
    virtual const char* what() const
    {
        return "B";
    }
    B() { printf("Created B at %X\n", this); }
    B(const B& b) { printf("Copied B from %X at %X\n", &b, this); } // make it copyable
    B& operator=(const B& b) { printf("Copied B from %X at %X\n", &b, this); return *this;}; // make it copyable
    B(const B&& b) { printf("Moved B from %X at %X\n", &b, this); } // make it movable

};

class C : public B
{
public:
    int q;

    C(int qq) { q = qq; printf("Created C at %X with q=%d\n", this, q); }
    C(const C& c) :B(c) { q = c.q; printf("Copied C from %X at %X\n", &c, this); } // make it copyable
    C& operator=(const C& c) { q = c.q; printf("Copied C from %X at %X\n", &c, this); return *this; }; // make it copyable
    C(const C&& c):B(std::move(c)) { q = std::move(c.q); printf("Moved C from %X at %X\n", &c, this); } // make it movable
};

int main()
{
    // Check does rethrow_exception copies underlying object
    try
    {
        B b; // B created
        throw std::move(b);
    }
    catch (...)
    {
        auto p = std::current_exception();
        try
        {
            std::rethrow_exception(std::move(p));
        }
        catch (...)
        {
            auto p = std::current_exception();
            try
            {
                std::rethrow_exception(p);
            }
            catch (B& b) // refered to last copy
            {
                printf("done with B at %X\n", &b);
            }
        }
    }


    printf("\n");
    // Try with dynamic_cast
    try {
        C c(12);
        throw std::move(c);
    }
    catch (...)
    {
        printf("Caught something\n");
        auto p = std::current_exception();
        try {
            std::rethrow_exception(p);
        }
        catch (std::exception& ex)
        {
            printf("Caught ex\n");
            if (A* a = dynamic_cast<A*>(&ex))
                printf("ex is A\n");
            if (B* b = dynamic_cast<B*>(&ex))
                printf("ex is B\n");
            if (C* c = dynamic_cast<C*>(&ex))
                printf("ex is also C with q=%d\n", c->q);
        }
    }
}

      

0


source







All Articles