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
?
source to share
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);
}
}
}
source to share