<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 3645: resize_and_overwrite is overspecified to call its callback with lvalues</title>
<meta property="og:title" content="Issue 3645: resize_and_overwrite is overspecified to call its callback with lvalues">
<meta property="og:description" content="C++ library issue. Status: C++23">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue3645.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#C++23">C++23</a> status.</em></p>
<h3 id="3645"><a href="lwg-defects.html#3645">3645</a>. <code>resize_and_overwrite</code> is overspecified to call its callback with lvalues</h3>
<p><b>Section:</b> 27.4.3.5 <a href="https://wg21.link/string.capacity">[string.capacity]</a> <b>Status:</b> <a href="lwg-active.html#C++23">C++23</a>
 <b>Submitter:</b> Arthur O'Dwyer <b>Opened:</b> 2021-11-28 <b>Last modified:</b> 2023-11-22</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#string.capacity">issues</a> in [string.capacity].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++23">C++23</a> status.</p>
<p><b>Discussion:</b></p>
<p>
27.4.3.5 <a href="https://wg21.link/string.capacity">[string.capacity]</a> p7 says:
</p>
<ul>
<li><p>[Let] <code><i>OP</i></code> be the expression <code>std::move(op)(p, n)</code>.</p></li>
<li><p>[<i>Precondition:</i>] <code><i>OP</i></code> does not throw an exception or modify <code>p</code> or <code>n</code>.</p></li>
</ul>
<p>
Notice that <code>p</code> and <code>n</code> above are lvalue expressions.
<p/>
Discussed with Mark Zeren, Casey Carter, Jonathan Wakely. We observe that:
<p/>
A. This wording requires vendors to reject
</p>
<blockquote><pre>
s.resize_and_overwrite(100, [](char*&amp;&amp;, size_t&amp;&amp;){ return 0; });
</pre></blockquote>
<p>
which is surprising.
<p/>
B. This wording requires vendors to accept
</p>
<blockquote><pre>
s.resize_and_overwrite(100, [](char*&amp;, size_t&amp;){ return 0; });
</pre></blockquote>
<p>
which is even more surprising, and also threatens to allow the user to corrupt 
the internal state (which is why we need to specify the Precondition above).
<p/>
C. A user who writes
</p>
<blockquote><pre>
s.resize_and_overwrite(100, [](auto&amp;&amp;, auto&amp;&amp;){ return 0; });
</pre></blockquote>
<p>
can detect that they're being passed lvalues instead of rvalues. If we change 
the wording to permit implementations to pass either lvalues or rvalues (their choice), 
then this will be detectable by the user, so we don't want that if we can help it.
</p>
<ol style="list-style-type:none">
<li><p>X. We want to enable implementations to say <code>move(op)(__p, __n)</code> 
and then use <code>__p</code> and <code>__n</code>.</p></li>
<li><p>Y. We have one implementation which wants to say <code>move(op)(data(), __n)</code>, 
which is not currently allowed, but arguably should be.</p></li>
<li><p>Z. We have to do or say something about disallowing writes to any 
internal state to which <code>Op</code> might get a reference.</p></li>
</ol>
<p>
Given all of this, Mark and Arthur think that the simplest way out is to say that the 
arguments are prvalues. It prevents X, but fixes the surprises in A, B, Y, Z. We 
could do this in the Let bullets. Either like so:
</p>
<ul>
<li><p>[Let] <code>p</code> be a prvalue of type <code>charT*</code> &hellip;</p></li>
<li><p><code>m</code> be a prvalue of type <code>size_type</code> equal to <code>n</code>,</p></li>
<li><p><code><i>OP</i></code> be the expression <code>std::move(op)(p, m)</code>.</p></li>
</ul>
<p>
or (Arthur's preference) by specifying prvalues in the expression <code><i>OP</i></code> itself:
</p>
<ul>
<li><p>[Let] <code><i>OP</i></code> be the expression <code>std::move(op)(auto(p), auto(n))</code>.</p></li>
</ul>
<p>
No matter which specification approach we adopt, we can also simplify the Preconditions bullet to:
</p>
<ul>
<li><p>[<i>Precondition:</i>] <code><i>OP</i></code> does not throw an exception.</p></li>
</ul>
<p>
because once the user is receiving prvalue copies, it will no longer be physically possible for the 
user to modify the library's original variables <code>p</code> and <code>n</code>.
</p>

<p><i>[2021-11-29; Arthur O'Dwyer provides wording]</i></p>


<p><i>[2022-01-30; Reflector poll]</i></p>

<p>
Set priority to 2 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/N4901" title=" Working Draft, Standard for Programming Language C++">N4901</a>.
</p>

<ol>

<li><p>Modify 27.4.3.5 <a href="https://wg21.link/string.capacity">[string.capacity]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;class Operation&gt; constexpr void resize_and_overwrite(size_type n, Operation op);
</pre>
<blockquote>
<p>
-7- Let
</p>
<ol style="list-style-type:none">
<li><p>(7.1) &mdash; <code>o = size()</code> before the call to <code>resize_and_overwrite</code>.</p></li>
<li><p>(7.2) &mdash; <code>k</code> be <code>min(o, n)</code>.</p></li>
<li><p>(7.3) &mdash; <code>p</code> be a <code>charT*</code>, such that the range <code>[p, p + n]</code> is valid 
and <code>this-&gt;compare(0, k, p, k) == 0</code> is <code>true</code> before the call. The values in the range 
<code>[p + k, p + n]</code> may be indeterminate (6.8.5 <a href="https://wg21.link/basic.indet">[basic.indet]</a>).</p></li>
<li><p>(7.4) &mdash; <code><i>OP</i></code> be the expression <code>std::move(op)(<ins>auto(</ins>p<ins>)</ins>, <ins>auto(</ins>n<ins>)</ins>)</code>.</p></li>
<li><p>(7.5) &mdash; <code>r = <i>OP</i></code>.</p></li>
</ol>
<p>
-8- <i>Mandates:</i> <code><i>OP</i></code> has an integer-like type (24.3.4.4 <a href="https://wg21.link/iterator.concept.winc">[iterator.concept.winc]</a>).
<p/>
-9- <i>Preconditions:</i>
</p>
<ol style="list-style-type:none">
<li><p>(9.1) &mdash; <code><i>OP</i></code> does not throw an exception <del>or modify <code>p</code> or <code>n</code></del>.</p></li>
<li><p>(9.2) &mdash; <code>r &ge; 0</code>.</p></li>
<li><p>(9.3) &mdash; <code>r &le; n</code>.</p></li>
<li><p>(9.4) &mdash; After evaluating <code><i>OP</i></code> there are no indeterminate values in the range 
<code>[p, p + r)</code>.</p></li>
</ol>
<p>
-10- <i>Effects:</i> Evaluates <code><i>OP</i></code>, replaces the contents of <code>*this</code> with <code>[p, p + r)</code>, 
and invalidates all pointers and references to the range <code>[p, p + n]</code>.
<p/>
-11- <i>Recommended practice:</i> Implementations should avoid unnecessary copies and allocations by, for example,
making <code>p</code> a pointer into internal storage and by restoring <code>*(p + r)</code> to <code>charT()</code> 
after evaluating <code><i>OP</i></code>.
</p>
</blockquote>
</blockquote>
</li>

</ol>
</blockquote>

<p><i>[2023-01-11; Jonathan Wakely provides new wording requested by LWG]</i></p>


<p><i>[Issaquah 2023-02-07; LWG]</i></p>

<p>Move to Immediate for C++23</p>

<p><i>[2023-02-13 Approved at February 2023 meeting in Issaquah. Status changed: Immediate &rarr; WP.]</i></p>



<p id="res-3645"><b>Proposed resolution:</b></p>

<p>
This wording is relative to <a href="https://wg21.link/N4917" title=" Working Draft, Standard for Programming Language C++">N4917</a>.
</p>

<ol>

<li><p>Modify 27.4.3.5 <a href="https://wg21.link/string.capacity">[string.capacity]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;class Operation&gt; constexpr void resize_and_overwrite(size_type n, Operation op);
</pre>
<blockquote>
<p>
-7- Let
</p>
<ol style="list-style-type:none">
<li><p>(7.1) &mdash; <code>o = size()</code> before the call to <code>resize_and_overwrite</code>.</p></li>
<li><p>(7.2) &mdash; <code>k</code> be <code>min(o, n)</code>.</p></li>
<li><p>(7.3) &mdash; <code>p</code> be a <ins>value of type</ins>
<code>charT*</code> <ins>or <code>charT* const</code></ins>,
such that the range <code>[p, p + n]</code> is valid
and <code>this-&gt;compare(0, k, p, k) == 0</code> is <code>true</code> before the call.
The values in the range
<code>[p + k, p + n]</code> may be indeterminate (6.8.5 <a href="https://wg21.link/basic.indet">[basic.indet]</a>).</p></li>
<li><p><ins>(7.?) &mdash;
<code>m</code> be a value of type <code>size_type</code> or
<code>const size_type</code> equal to <code>n</code>.
</ins></p></li>
<li><p>(7.4) &mdash; <code><i>OP</i></code> be the expression <code>std::move(op)(p, <del>n</del><ins>m</ins>)</code>.</p></li>
<li><p>(7.5) &mdash; <code>r = <i>OP</i></code>.</p></li>
</ol>
<p>
-8- <i>Mandates:</i> <code><i>OP</i></code> has an integer-like type (24.3.4.4 <a href="https://wg21.link/iterator.concept.winc">[iterator.concept.winc]</a>).
<p/>
-9- <i>Preconditions:</i>
</p>
<ol style="list-style-type:none">
<li><p>(9.1) &mdash; <code><i>OP</i></code> does not throw an exception or modify <code>p</code> or <code><del>n</del><ins>m</ins></code>.</p></li>
<li><p>(9.2) &mdash; <code>r &ge; 0</code>.</p></li>
<li><p>(9.3) &mdash; <code>r &le; <del>n</del><ins>m</ins></code>.</p></li>
<li><p>(9.4) &mdash; After evaluating <code><i>OP</i></code> there are no indeterminate values in the range
<code>[p, p + r)</code>.</p></li>
</ol>
<p>
-10- <i>Effects:</i> Evaluates <code><i>OP</i></code>, replaces the contents of <code>*this</code> with <code>[p, p + r)</code>,
and invalidates all pointers and references to the range <code>[p, p + n]</code>.
<p/>
-11- <i>Recommended practice:</i> Implementations should avoid unnecessary copies and allocations by, for example,
making <code>p</code> a pointer into internal storage and by restoring <code>*(p + r)</code> to <code>charT()</code>
after evaluating <code><i>OP</i></code>.
</p>
</blockquote>
</blockquote>
</li>

</ol>






</body>
</html>
