How does std :: current_exception work?

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 am throwing a class object myclass

and using std :: current_exception()

in a block catch(...)

to get std :: exception_ptr

. Later I use std :: rethrow_exception

to get the exception again and I catch it, this time with catch(const myclass &)

, allowing me to call f()

and print , for example Hello from myclass!

.

Now. I imagine how I could implement something similar to std :: exception_ptr

: a pointer to the base class from which the template wrapper is inherited for every possible type, and some virtual method rethrow

that allows the exception to be thrown again. So far so good.

Now how does it work std :: current_exception()

? How is this implemented? I tried to test it using the Xcode me, but I have good flashing question mark: ?

. Is this some kind of primitive in C ++ 11? Like, for example, decltype

or sizeof

? Or is there another way to access the exception hidden in this catch(...)

?

For example, is there a way to just print the 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 am guessing I std :: current_exception()

will use some similar way to access the exception, make a copy of it, and create an instance std :: exception_ptr

that can be restored later.

Am I missing something? I've tried something trivial like catch(auto x)

, but it doesn't seem to do the job.

+3


source to share


1 answer


Before std::exception_ptr

was boost::exception_ptr

, who tries to implement this functionality without direct language support, and therefore requires more working code to work, With Boost, you need to wrap the exception at a point throw

with boost::enable_current_exception

and instead take out the wrapper. I haven't actually looked into the implementation, but my guess is that the shell copy constructor sets a local thread pointer pointing to itself ( throw

must copy its argument) which boost::current_exception

then retrieves (perhaps copying the exception to free storage first so it can survive the block catch

). To continue working, the catch (T x)

shell must wrap the original exception, inheriting from it, which makes it impossible to use with primitive types.

Another way is to copy the original, set the local stream pointer to point to the copy, and discard the original. This method works for any throwable type, but current_exception

will refer to a different instance than the one used to o initialize the parameter catch

.



Now std::exception_ptr

has direct language support and doesn't need to go through hoops or do over-copying to archive this, but the basic idea is the same: store the exception in a type-erasure container that can restore it at the point of being thrown and point to it.

+1


source







All Articles