This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
Section: 33.4.4.2 [thread.jthread.cons] Status: WP Submitter: Nicole Mazzuca Opened: 2022-09-22 Last modified: 2022-11-17
Priority: 3
View all issues with WP status.
Discussion:
In the Postconditions element of jthread& jthread::operator=(jthread&&) (33.4.4.2 [thread.jthread.cons] p13), we have the following:
Postconditions: x.get_id() == id(), and get_id() returns the value of x.get_id() prior to the assignment. ssource has the value of x.ssource prior to the assignment and x.ssource.stop_possible() is false.
Assume j is a joinable jthread. Then, j = std::move(j); results in the following post-conditions:
Let old_id = j.get_id() (and since j is joinable, old_id != id())
Since x.get_id() == id(), j.get_id() == id()
Since get_id() == old_id, j.get_id() == old_id
Thus, id() == j.get_id() == old_id, and old_id != id(), which is a contradiction.
One can see that these postconditions are therefore unimplementable.
Two standard libraries – the MSVC STL and libstdc++ – currently implement jthread. The MSVC STL chooses to follow the letter of the Effects element, which results in unfortunate behavior. It first request_stop()s, then join()s; then, it assigns the values over. This results in j.get_id() == id() – this means that std::swap(j, j) stops and joins j. libstdc++ chooses instead to implement this move assignment operator via the move-swap idiom. This results in j.get_id() == old_id, and std::swap(j, j) is a no-op. It is the opinion of the issue writer that libstdc++'s choice is the correct one, and should be taken into the standard.[2022-09-28; Reflector poll]
Set priority to 3 after reflector poll.
[2022-09-28; Jonathan provides wording]
[2022-09-29; Reflector poll]
Set status to Tentatively Ready after five votes in favour during reflector poll.
[2022-11-12 Approved at November 2022 meeting in Kona. Status changed: Voting → WP.]
Proposed resolution:
This wording is relative to N4917.
Modify 33.4.4.2 [thread.jthread.cons] as indicated:
jthread& operator=(jthread&& x) noexcept;-12- Effects: If &x == this is true, there are no effects. Otherwise, if joinable() is true, calls request_stop() and then join()
. Assigns, then assigns the state of x to *this and sets x to a default constructed state.-13- Postconditions:
x.get_id() == id() andget_id() returns the value of x.get_id() prior to the assignment. ssource has the value of x.ssource prior to the assignmentand x.ssource.stop_possible() is false.-14- Returns: *this.