<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 4158: packaged_task::operator= should abandon its shared state</title>
<meta property="og:title" content="Issue 4158: packaged_task::operator= should abandon its shared state">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue4158.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="4158"><a href="lwg-active.html#4158">4158</a>. <code>packaged_task::operator=</code> should abandon its shared state</h3>
<p><b>Section:</b> 32.10.10.2 <a href="https://wg21.link/futures.task.members">[futures.task.members]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Jonathan Wakely <b>Opened:</b> 2024-09-19 <b>Last modified:</b> 2024-10-03</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#futures.task.members">issues</a> in [futures.task.members].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The <code class='backtick'>packaged_task</code> move assignment operator is specified to release
the previous shared state. This means it releases ownership, but does
not make the shared state ready. Any future that shares ownership of the
shared state will never receive a result, because the provider is gone.
This means that any thread that waits on the future will block forever.
</p>
<p>
There is a note on <code class='backtick'>packaged_task::reset()</code> which claims that assignment
abandons the state, which is not supported by any normative wording:
</p>
<blockquote>
<pre>void reset();</pre>
<p>
-26- <i>Effects</i>:
As if <code class='backtick'>*this = packaged_task(std::move(f))</code>,
where <code class='backtick'>f</code> is the task stored in <code class='backtick'>*this</code>.
</p>
<p>
[<i>Note 2</i>: This constructs a new shared state for <code class='backtick'>*this</code>.
The old state is abandoned (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>).
&mdash; <i>end note</i>]
</p>
</blockquote>
<p>
Presumably, the intended behaviour of assignment was to abandon the
shared state,
i.e.  make it ready with a <code class='backtick'>broken_promise</code> error, and then release it.
That is what the <code class='backtick'>std::promise</code> move assignment does
(see 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a> p9).
Both libstdc++ and libc++ abandon the state, despite what the standard says.
</p>

<p><i>[2024-10-02; Reflector poll]</i></p>

<p>
Set priority to 3 after reflector poll.
</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">

<p>
This wording is relative to <a href="https://wg21.link/N4988" title=" Working Draft, Programming Languages — C++">N4988</a>.
</p>
<ol>
<li><p>Modify 32.10.10.2 <a href="https://wg21.link/futures.task.members">[futures.task.members]</a> as indicated:</p>
<blockquote>
<pre>
packaged_task&amp; operator=(packaged_task&amp;&amp; rhs) noexcept;
</pre>
<p>-11- <i>Effects</i>:
<ol style="list-style-type: none">
<li>(11.1) &mdash;
<del>Releases</del> <ins>Abandons</ins>
any shared state (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>);
</li>
<li>(11.2) &mdash;
calls <code class='backtick'>packaged_task(std::move(rhs)).swap(*this)</code>.
</li>
</ol>
</p>
<p><ins>-?- <i>Returns</i>: <code class='backtick'>*this</code>.</ins></p>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2024-10-02; Jonathan provides improved wording]</i></p>

<p>
Following reflector discussion, remove the "Releases any shared state" text
completely.
The remaining effects imply that the state will be abandoned anyway.
This makes it safe against self-assignment.
</p>

<p><i>[2024-10-02; LWG telecon]</i></p>

<p>
Agreed to change <code class='backtick'>promise</code> the same way, which is safe for self-assignment
and matches what all three of libstdc++, libc++ and MSVC do today.
Ask SG1 to review.
</p>



<p id="res-4158"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/N4988" title=" Working Draft, Programming Languages — C++">N4988</a>.
</p>
<ol>

<li><p>Modify 32.10.6 <a href="https://wg21.link/futures.promise">[futures.promise]</a> as indicated:</p>
<blockquote>
<pre>
promise&amp; operator=(promise&amp;&amp; rhs) noexcept;
</pre>
<p>-9- <i>Effects</i>:
<del>
Abandons any shared state (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>) and then as if
</del>
<ins>Equivalent to</ins>
<code class='backtick'>promise(std::move(rhs)).swap(*this)</code>.
</p>
<p>-10- <i>Returns</i>: <code class='backtick'>*this</code>.</p>
</blockquote>
</li>
<li><p>Modify 32.10.10.2 <a href="https://wg21.link/futures.task.members">[futures.task.members]</a> as indicated:</p>
<blockquote>
<pre>
packaged_task&amp; operator=(packaged_task&amp;&amp; rhs) noexcept;
</pre>
<p>-11- <i>Effects</i>:
<ol style="list-style-type: none">
<li><del>(11.1) &mdash;
Releases
any shared state (32.10.5 <a href="https://wg21.link/futures.state">[futures.state]</a>);</del>
</li>
<li><del>(11.2) &mdash;
calls</del>
<ins>Equivalent to</ins>
<code class='backtick'>packaged_task(std::move(rhs)).swap(*this)</code>.
</li>
</ol>
</p>
<p><ins>-?- <i>Returns</i>: <code class='backtick'>*this</code>.</ins></p>
</blockquote>
</li>
</ol>





</body>
</html>
