Consider the following example:
class myclass
{
public:
void f() const
{
std :: cout << "Hello from myclass!" << std :: endl;
}
};
int main()
{
std :: exception_ptr x;
try
{
throw myclass();
}
catch(...)
{
x = std :: current_exception();
}
try
{
std :: rethrow_exception(x);
}
catch(const myclass & n)
{
n.f();
}
}
Here I throw an object of class myclass
and use std :: current_exception()
in the catch(...)
block to get a std :: exception_ptr
. Later I use std :: rethrow_exception
to get the exception thrown again and I catch it, this time with catch(const myclass &)
, that allows me to, e.g., call f()
and get Hello from myclass!
printed out.
Now. I kind of imagine how I could implement something similar to std :: exception_ptr
: a pointer to a base class, from which a template wrapper for each possible type inherits, and some rethrow
virtual method that allows to throw again the exception. So far so good.
Now, how does std :: current_exception()
work? How is it implemented? I tried to inspect it using my Xcode but I got a nice flashing question mark: ?
. Is this some kind of primitive in C++11? Like, e.g., decltype
or sizeof
? Or is there another way to access the exception hidden in that catch(...)
?
For example, is there a way to just print out an exception, whatever it is? Something like:
template <typename type> void printme(const type & exception)
{
try
{
throw exception;
}
catch(...)
{
std :: cout << /* SOME MAGIC HERE */ << std :: endl;
}
}
I guess that std :: current_exception()
would be using some similar way to access the exception, make a copy of it, and instantiate an appropriate std :: exception_ptr
that can be later rethrown.
So am I missing something? I tried something trivial like catch(auto x)
but it doesn't seem to do the job.
Before std::exception_ptr
there was boost::exception_ptr
that attempts to implement this functionality without direct language support and consequently requires more boilerplate code to work. With Boost, you have to wrap the exception at the point of throw
with boost::enable_current_exception
and throw the wrapper instead. I have not actually studied the implementation, but I imagine that the wrapper's copy constructor sets a thread-local pointer to point to itself (throw
must copy its argument) which boost::current_exception
then retrieves (possibly copying the exception to free store first, so that it can outlive the catch
block). For catch (T x)
to still work the wrapper has to wrap the original exception by inheriting from it, which makes it impossible to use with primitive types.
Another way is to copy the original, set the thread-local pointer to point to the copy and throw the original. This way works for any throwable type but current_exception
would refer to a different instance than the one used o initialize the catch
parameter.
Now std::exception_ptr
has direct language support and does not have to jump through hoops or do excessive copying to achieve this but the basic idea is the same: store the exception in a type-erased container that can rethrow it at the point of throw and point to that.