C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::future::get_exception()

From: Jonathan Wakely <cxx_at_[hidden]>
Date: Sat, 7 Jun 2025 15:15:50 +0100
On Sat, 7 Jun 2025, 14:48 Stewart Becker via Std-Proposals, <
std-proposals_at_[hidden]> wrote:

> There are times when it would be useful to determine if a std::future
> would throw an exception on calling .get(), but we don't want to
> actually throw an exception. One case is if we have a means to continue
> if the future fails to successfully get() a result, e.g. in a when_any
> or or_else -like function. In these cases, it is more efficient to use
> a a simple branch rather than throwing and catching.
>
> Another case is when throwing and catching exceptions is not permitted
> by coding standards. Embedded programming commonly has coding standard
> forbidding throw/catch. Yet a std::promise may be fulfilled via
> set_exception, meaning that the try/throw/catch mechanism of exception
> handling is not required to put an exception into the shared channel
> between promises and futures - try/catch is only needed on std::future's
> end of the channel.
>
> A std::future::get_exception counterpart to std::promise::set_exception
> would allow both the existence of an exception, and its nature, to be
> obtained without the overhead of wrapping a try/catch around
> std::future::get(). Invoking get_exception on a future f would be
> defined behaviour if-and-only-if calling f.get() is defined behaviour,
> and should return a null std::exception_ptr if-and-only-if f.get()
> doesn't throw. Otherwise it returns a std::exception_ptr wrapping the
> exception that f.get() would throw. Calling f.get_exception() wouldn't
> cause calling f.get() to become UB, and so get_exception() could be a
> const member function of std::future.
>
>
> *Alternatives*
>
> It might be possible, within a given codebase, to achieve equivalent
> functionality by the use of std::future<std::expected<T, exception_ptr>>
> *and* careful definition of the functions used with std::future's
> generators std::async & std::packaged_task. However, this has two
> drawbacks:
>
> 1. std::expected does not support wrapping references - one has to wrap
> the reference somehow, leading to more complicated code. This could be
> mitigated by having std::expected support references. This idea was
> mentioned (but not proposed) in P2988r0 and anyway was subsequently
> dropped in later revisions of that paper. I am not aware of any other
> work in this area.
>

I expect it will come back and we'll get expected<T&,E>, but not as part of
the same proposal as optional<T&>.

If we get it for C++29 then this point is no longer relevant, since your
idea couldn't get accepted before C++29 anyway.



> 2. Regardless, it is still possible for std::future<std::expected<T,
> std::exception_ptr>>::get() to throw. To avoid this, care must be taken
> with the functions given to std::future's sources (std::asyc,
> std::packaged_task etc.) to ensure than the exception is supplied only
> via a std::unexpected<std::exception_ptr>. Furthermore, the consumer of
> the future must know that this is the case. Generic code using this
> approach would still benefit from being able to tell if the future.get()
> will throw or not.
>


Right, but I still think we could improve your program by using expected.

What if instead of get() and get_exception() we had get() and get_result()
where the latter returns expected<R,exception_ptr>?




>
> *Thoughts on implementation*
>
> Regarding implentation, I have looked at the Microsoft, GNU and LLVM
> implementations of std::future and they all use a shared state object
> that has an exception_ptr data member. Indeed, it is difficult to
> imagine how promises and futures could work without such a data member
> somewhere. If we allow get_exception() to exhibit UB whenever calling
> get() is also UB, then I _think_ that the implementation is simply a
> matter of wait()ing for the future to be ready, then returning this data
> member.
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2025-06-07 14:16:11