This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++23 status.

2697. [concurr.ts] Behavior of future/shared_future unwrapping constructor when given an invalid future

Section: 99 [concurr.ts::futures.unique_future], 99 [concurr.ts::futures.shared_future] Status: C++23 Submitter: Tim Song Opened: 2016-04-22 Last modified: 2023-11-22

Priority: 2

View all issues with C++23 status.

Discussion:

Addresses: concurr.ts

In the concurrency TS, the future/shared_future unwrapping constructors

future(future<future<R>>&&) noexcept;
shared_future(future<shared_future<R>>&& rhs) noexcept;

appear to implicitly require rhs be valid (e.g., by referring to its shared state, and by requiring a valid() == true postcondition). However, they are also marked noexcept, suggesting that they are wide-contract, and also makes the usual suggested handling for invalid futures, throwing a future_error, impossible.

Either the noexcept should be removed, or the behavior with an invalid future should be specified.

Original resolution alternative #1 [NOT CHOSEN]:

This wording is relative to N4577.

Strike the noexcept on these constructors in 99 [concurr.ts::futures.unique_future]/1-2 and 99 [concurr.ts::futures.shared_future]/1-2, and optionally add a Requires: rhs.valid() == true paragraph.

[2016-11-12, Issaquah]

Sat PM: We prefer alternative #2 - Move to review

[2018-06; Rapperswil, Wednesday evening session]

DR: there is a sentence ended followed by an entirely new sentence
JM: so the period should be a semicolon in both edits
MC: ACTION I can make the change editorially
ACTION move to Ready

[2018-11, Adopted in San Diego]

Proposed resolution:

This wording is relative to N4577.

Alternative #2: Specify that an empty (shared_)future object is constructed if rhs is invalid, and adjust the postcondition accordingly.

  1. Edit 99 [concurr.ts::futures.unique_future] as indicated:

    future(future<future<R>>&& rhs) noexcept;
    

    -3- Effects: If rhs.valid() == false, constructs an empty future object that does not refer to a shared state. Otherwise, cConstructs a future object from the shared state referred to by rhs. T; the future becomes ready when one of the following occurs:

    • Both the rhs and rhs.get() are ready. The value or the exception from rhs.get() is stored in the future's shared state.

    • rhs is ready but rhs.get() is invalid. An exception of type std::future_error, with an error condition of std::future_errc::broken_promise is stored in the future's shared state.

    -4- Postconditions:

    • valid() == truevalid() returns the same value as rhs.valid() prior to the constructor invocation..

    • rhs.valid() == false.

  2. Edit 99 [concurr.ts::futures.shared_future] as indicated:

    shared_future(future<shared_future<R>>&& rhs) noexcept;
    

    -3- Effects: If rhs.valid() == false, constructs an empty shared_future object that does not refer to a shared state. Otherwise, cConstructs a shared_future object from the shared state referred to by rhs. T; the shared_future becomes ready when one of the following occurs:

    • Both the rhs and rhs.get() are ready. The value or the exception from rhs.get() is stored in the shared_future's shared state.

    • rhs is ready but rhs.get() is invalid. The shared_future stores an exception of type std::future_error, with an error condition of std::future_errc::broken_promise.

    -4- Postconditions:

    • valid() == truevalid() returns the same value as rhs.valid() prior to the constructor invocation..

    • rhs.valid() == false.