32 Thread support library [thread]

32.9 Futures [futures]

32.9.8 Class template shared_­future [futures.shared.future]

The class template shared_­future defines a type for asynchronous return objects which may share their shared state with other asynchronous return objects.
A default-constructed shared_­future object has no shared state.
A shared_­future object with shared state can be created by conversion from a future object and shares its shared state with the original asynchronous provider of the shared state.
The result (value or exception) of a shared_­future object can be set by calling a respective function on an object that shares the same shared state.
[Note 1:
Member functions of shared_­future do not synchronize with themselves, but they synchronize with the shared state.
— end note]
The effect of calling any member function other than the destructor, the move-assignment operator, the copy-assignment operator, or valid() on a shared_­future object for which valid() == false is undefined.
[Note 2:
It is valid to copy or move from a shared_­future object for which valid() is false.
— end note]
Recommended practice: Implementations should detect this case and throw an object of type future_­error with an error condition of future_­errc​::​no_­state.
namespace std { template<class R> class shared_future { public: shared_future() noexcept; shared_future(const shared_future& rhs) noexcept; shared_future(future<R>&&) noexcept; shared_future(shared_future&& rhs) noexcept; ~shared_future(); shared_future& operator=(const shared_future& rhs) noexcept; shared_future& operator=(shared_future&& rhs) noexcept; // retrieving the value see below get() const; // functions to check state bool valid() const noexcept; void wait() const; template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const; template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const; }; }
The implementation provides the template shared_­future and two specializations, shared_­future<R&> and shared_­future<void>.
These differ only in the return type and return value of the member function get, as set out in its description, below.
shared_future() noexcept;
Effects: The object does not refer to a shared state.
Postconditions: valid() == false.
shared_future(const shared_future& rhs) noexcept;
Effects: The object refers to the same shared state as rhs (if any).
Postconditions: valid() returns the same value as rhs.valid().
shared_future(future<R>&& rhs) noexcept; shared_future(shared_future&& rhs) noexcept;
Effects: Move constructs a shared_­future object that refers to the shared state that was originally referred to by rhs (if any).
Postconditions:
  • valid() returns the same value as rhs.valid() returned prior to the constructor invocation.
  • rhs.valid() == false.
~shared_future();
Effects:
shared_future& operator=(shared_future&& rhs) noexcept;
Effects:
Postconditions:
  • valid() returns the same value as rhs.valid() returned prior to the assignment.
  • rhs.valid() == false.
shared_future& operator=(const shared_future& rhs) noexcept;
Effects:
  • Releases any shared state ([futures.state]);
  • assigns the contents of rhs to *this.
    [Note 3:
    As a result, *this refers to the same shared state as rhs (if any).
    — end note]
Postconditions: valid() == rhs.valid().
const R& shared_future::get() const; R& shared_future<R&>::get() const; void shared_future<void>::get() const;
[Note 4:
As described above, the template and its two required specializations differ only in the return type and return value of the member function get.
— end note]
[Note 5:
Access to a value object stored in the shared state is unsynchronized, so operations on R might introduce a data race ([intro.multithread]).
— end note]
Effects: wait()s until the shared state is ready, then retrieves the value stored in the shared state.
Returns:
  • shared_­future​::​get() returns a const reference to the value stored in the object's shared state.
    [Note 6:
    Access through that reference after the shared state has been destroyed produces undefined behavior; this can be avoided by not storing the reference in any storage with a greater lifetime than the shared_­future object that returned the reference.
    — end note]
  • shared_­future<R&>​::​get() returns the reference stored as value in the object's shared state.
  • shared_­future<void>​::​get() returns nothing.
Throws: The stored exception, if an exception was stored in the shared state.
bool valid() const noexcept;
Returns: true only if *this refers to a shared state.
void wait() const;
Effects: Blocks until the shared state is ready.
template<class Rep, class Period> future_status wait_for(const chrono::duration<Rep, Period>& rel_time) const;
Effects: None if the shared state contains a deferred function ([futures.async]), otherwise blocks until the shared state is ready or until the relative timeout ([thread.req.timing]) specified by rel_­time has expired.
Returns:
  • future_­status​::​deferred if the shared state contains a deferred function.
  • future_­status​::​ready if the shared state is ready.
  • future_­status​::​timeout if the function is returning because the relative timeout ([thread.req.timing]) specified by rel_­time has expired.
Throws: timeout-related exceptions ([thread.req.timing]).
template<class Clock, class Duration> future_status wait_until(const chrono::time_point<Clock, Duration>& abs_time) const;
Effects: None if the shared state contains a deferred function ([futures.async]), otherwise blocks until the shared state is ready or until the absolute timeout ([thread.req.timing]) specified by abs_­time has expired.
Returns:
  • future_­status​::​deferred if the shared state contains a deferred function.
  • future_­status​::​ready if the shared state is ready.
  • future_­status​::​timeout if the function is returning because the absolute timeout ([thread.req.timing]) specified by abs_­time has expired.
Throws: timeout-related exceptions ([thread.req.timing]).