Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

std::any and std::exception_ptr

45 views
Skip to first unread message

johannes.g...@gmail.com

unread,
Dec 21, 2015, 8:48:54 AM12/21/15
to
N3804 proposes the introduction of std::any.

Now, C++ already has an "any"-like type, namely std::exception_ptr. Semantically, after the introduction of std::any, exception_ptr will be a special case of std::any, namely a semantical std::any initialized by a caught exception.

Wouldn't it make sense to make these two interoperate nicely? In particular,

** std::exception_ptr should be able to be converted into a std::any, as, currently, the only way of looking into an exception_ptr is re-throwing and catching immediately (please correct me if I am wrong).

** std::rethrow_exception should accept a std::any, throwing its contents (not the std::any itself). This would permit the preparation of a potential exception in advance and throwing it at a later point in time.

Best regards,
Johannes

woodb...@gmail.com

unread,
Dec 21, 2015, 12:06:17 PM12/21/15
to
Run away from that stuff.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Paavo Helde

unread,
Dec 21, 2015, 4:04:16 PM12/21/15
to
johannes.g...@gmail.com wrote in
news:35bf6c89-882c-4707...@googlegroups.com:

> N3804 proposes the introduction of std::any.
>
> Now, C++ already has an "any"-like type, namely std::exception_ptr.
> Semantically, after the introduction of std::any, exception_ptr will
> be a special case of std::any, namely a semantical std::any
> initialized by a caught exception.
>
> Wouldn't it make sense to make these two interoperate nicely?

These look similar, but the mechanisms are different. Exception handling
is all about derived classes and finding the catch handler of the correct
base class type, whereas std::any does not recognize derived classes at
all IIRC. Exception handling is also pretty slow. This probably means
that the underlying implementations must remain pretty different. This
does not mean that the conversion between two is not possible, only that
it might not be so trivial.

> In
> particular,
>
> ** std::exception_ptr should be able to be converted into a std::any,
> as, currently, the only way of looking into an exception_ptr is
> re-throwing and catching immediately (please correct me if I am
> wrong).
>
> ** std::rethrow_exception should accept a std::any, throwing its
> contents (not the std::any itself). This would permit the preparation
> of a potential exception in advance and throwing it at a later point
> in time.

This can be already done via std::make_exception_ptr().

Cheers
Paavo

Öö Tiib

unread,
Dec 21, 2015, 5:28:06 PM12/21/15
to
On Monday, 21 December 2015 15:48:54 UTC+2, johannes.g...@gmail.com wrote:
> N3804 proposes the introduction of std::any.
>
> Now, C++ already has an "any"-like type, namely std::exception_ptr.
> Semantically, after the introduction of std::any, exception_ptr will be
> a special case of std::any, namely a semantical std::any initialized by
> a caught exception.

The named things are different: 'std::exception_ptr' is NullablePointer
that has deeper knowledge of exception throwing mechanics and contains
some sort of reference counting; 'std::any' is singular container of
single object of whatever type.

>
> Wouldn't it make sense to make these two interoperate nicely? In particular,
>
> ** std::exception_ptr should be able to be converted into a std::any,
> as, currently, the only way of looking into an exception_ptr is
> re-throwing and catching immediately (please correct me if I am wrong).

May be there is come context where that may make sense. What is bad
about re-throwing and catching?

>
> ** std::rethrow_exception should accept a std::any, throwing its
> contents (not the std::any itself). This would permit the preparation
> of a potential exception in advance and throwing it at a later point
> in time.

That is already possible with 'std::make_exception_ptr' and
'std::rethrow_exception' so I see no value added. Also I think that
it is the main point of 'std::exception_ptr' ... so someone who finds
that constructing exceptions is expensive can throw same exception object
over and over from potentially many threads and potentially at same time.

For 'boost::any' I have found no purpose; on all cases I have found
'boost::variant' easier to use.

johannes.g...@gmail.com

unread,
Dec 22, 2015, 3:53:16 AM12/22/15
to
> The named things are different: 'std::exception_ptr' is NullablePointer
> that has deeper knowledge of exception throwing mechanics and contains
> some sort of reference counting; 'std::any' is singular container of
> single object of whatever type.

Well, but it is (conceptually) simple to implement one in terms of the other. A std::exception_ptr can be thought of as being a std::shared_ptr<std::any>, and std::any can be implemented by abusing a std::exception_ptr, see here:

http://stackoverflow.com/questions/34391357/stdany-by-stdexception-ptr

> > ** std::exception_ptr should be able to be converted into a std::any,
> > as, currently, the only way of looking into an exception_ptr is
> > re-throwing and catching immediately (please correct me if I am wrong).
>
> May be there is come context where that may make sense. What is bad
> about re-throwing and catching?

Suppose there is some sub-task which might result in an exception, which is caught and stored as a std::exception_ptr. Now we want to convert potential exceptions into an error code at the caller's side. Does it really make sense to establish a whole try-catch machinery just in order to figure out what kind of exception was thrown, in particular since try/catch is relatively slow and some coding guidelines forbid it? In addition, as soon as there is std::any in the standard, infrastructure will arise for handling std::any. If exception_ptrs are a thing of their own, they will never able to be used together with this infrastructure.

Note that if an exception_ptr is convertible to a std::any, it will become possible to do much more useful things in a catch-all clause.

> > ** std::rethrow_exception should accept a std::any, throwing its
> > contents (not the std::any itself). This would permit the preparation
> > of a potential exception in advance and throwing it at a later point
> > in time.
>
> That is already possible with 'std::make_exception_ptr' and
> 'std::rethrow_exception' so I see no value added. Also I think that
> it is the main point of 'std::exception_ptr' ... so someone who finds
> that constructing exceptions is expensive can throw same exception object
> over and over from potentially many threads and potentially at same time.

True, I missed that point. Nevertheless, with the current proposal, it will not be possible to throw the *contents* of a std::any unless you know which types it may contain. Throwing a std::any is, however, easy to implement if std::any supports it. Let us assume any is implemented as holding a unique_ptr to a polymorphic holder class any_value. Then you could do something like:

struct any {
void throwme () { m_val->throwme(); }
private:
unique_ptr<any_value> m_val;
}

struct any_value {
//...
virtual void throwme () = 0;
}

template <class T>
struct any_value<T> : any_value {
//...
void throwme () override { throw m_v; }

private:
T m_v;
}

This is impossible if std::any does not support it, hence it should be included in the first place.

Öö Tiib

unread,
Dec 22, 2015, 8:14:04 AM12/22/15
to
On Tuesday, 22 December 2015 10:53:16 UTC+2, johannes.g...@gmail.com wrote:
> > The named things are different: 'std::exception_ptr' is NullablePointer
> > that has deeper knowledge of exception throwing mechanics and contains
> > some sort of reference counting; 'std::any' is singular container of
> > single object of whatever type.
>
> Well, but it is (conceptually) simple to implement one in terms of the other. A std::exception_ptr can be thought of as being a std::shared_ptr<std::any>, and std::any can be implemented by abusing a std::exception_ptr, see here:
>
> http://stackoverflow.com/questions/34391357/stdany-by-stdexception-ptr

The 'exception_ptr' can have alternative underlying storage and mechanics
because exceptions are propagated by alternative mechanics. Exception
handling is optimized to be cheap when exceptions are not thrown for
cost of being expensive when thrown. So exceptions should not be used
as another way of returning (or even storing) of things.

>
> > > ** std::exception_ptr should be able to be converted into a std::any,
> > > as, currently, the only way of looking into an exception_ptr is
> > > re-throwing and catching immediately (please correct me if I am wrong).
> >
> > May be there is come context where that may make sense. What is bad
> > about re-throwing and catching?
>
> Suppose there is some sub-task which might result in an exception,
> which is caught and stored as a std::exception_ptr. Now we want to
> convert potential exceptions into an error code at the caller's side.

So why we don't want to throw exceptions that carry error codes?
But OK, lets say we have good reasons.

> Does it really make sense to establish a whole try-catch machinery
> just in order to figure out what kind of exception was thrown, in
> particular since try/catch is relatively slow and some coding
> guidelines forbid it? In addition, as soon as there is std::any in
> the standard, infrastructure will arise for handling std::any.
> If exception_ptrs are a thing of their own, they will never able to
> be used together with this infrastructure.

The more I think of it the more it feels like danger of throwing moved
from objects or the like.

>
> Note that if an exception_ptr is convertible to a std::any, it will become possible to do much more useful things in a catch-all clause.

I do not see any safe way to convert a ref-counted pointer into container.
It must involve making a copy of pointed at object into container.

>
> > > ** std::rethrow_exception should accept a std::any, throwing its
> > > contents (not the std::any itself). This would permit the preparation
> > > of a potential exception in advance and throwing it at a later point
> > > in time.
> >
> > That is already possible with 'std::make_exception_ptr' and
> > 'std::rethrow_exception' so I see no value added. Also I think that
> > it is the main point of 'std::exception_ptr' ... so someone who finds
> > that constructing exceptions is expensive can throw same exception object
> > over and over from potentially many threads and potentially at same time.
>
> True, I missed that point. Nevertheless, with the current proposal, it will not be possible to throw the *contents* of a std::any unless you know which types it may contain. Throwing a std::any is, however, easy to implement if std::any supports it. Let us assume any is implemented as holding a unique_ptr to a polymorphic holder class any_value.

The *contents* of std::any can not be taken out of it, 'any_cast's return
references and it is impossible to throw references. Construct like
'throw *this;' makes copy of this object. It is not good idea to do
lot of chemistry in constrained in unknown ways situations where
exceptions are thrown.

You keep conflating a ref-counted pointer that is perhaps anyway
used internally in exception throwing mechanics and a firm container that
is even encouraged not to use dynamic allocations for storing small
objects (that exceptions often are) in it.
0 new messages