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.

### 3788. `jthread::operator=(jthread&&)` postconditions are unimplementable under self-assignment

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.

1. 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()` 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`.

   > > -14- Returns: `*this`.