<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2705: Questionable precondition on Sequence containers a.assign(n, t)</title>
<meta property="og:title" content="Issue 2705: Questionable precondition on Sequence containers a.assign(n, t)">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2705.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="2705"><a href="lwg-active.html#2705">2705</a>. Questionable precondition on Sequence containers <code>a.assign(n, t)</code></h3>
<p><b>Section:</b> 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Kazutoshi Satoda <b>Opened:</b> 2016-05-08 <b>Last modified:</b> 2020-09-06</p>
<p><b>Priority: </b>3
</p>
<p><b>View other</b> <a href="lwg-index-open.html#sequence.reqmts">active issues</a> in [sequence.reqmts].</p>
<p><b>View all other</b> <a href="lwg-index.html#sequence.reqmts">issues</a> in [sequence.reqmts].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Please look through the following modifications on a value <code>v</code> of type <code>vector&lt;T&gt;</code>:
</p>
<blockquote><pre>
assert(v.size() &gt; 0);
v.push_back(v[0]);
v.insert(v.begin(), v[0]);
v.resize(v.size() * 2, v[0]);
v.assign(v.size() * 2, v[0]);
</pre></blockquote>
<p>
All of these use an element of itself which may be moved or destroyed by
the modification.
<p/>
From what I see so far, the first three are required to work. Please
see library issue <a href="lwg-closed.html#526" title="Is it undefined if a function in the standard changes in parameters? (Status: NAD)">526</a><sup><a href="https://cplusplus.github.io/LWG/issue526" title="Latest snapshot">(i)</a></sup> for validity of them.
<p/>
But only the last one is undefined because it violates a precondition of
a sequence container operation. I think this is too subtle.
<p/>
Should it be like that, really?
<p/>
The precondition is in Table 107 "Sequence container requirements" at the next 
of 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a> p3.
</p>
<blockquote>
<p>
In Tables 107 and 108, <code>X</code> denotes a sequence container class,
<code>a</code> denotes a value of <code>X</code> containing elements of type <code>T</code>,
[&hellip;] <code>n</code> denotes a value of <code>X::size_type</code>,
[&hellip;] <code>t</code> denotes an lvalue or a <code>const</code> rvalue of <code>X::value_type</code>,
[&hellip;]
</p>
<p>[&hellip;]</p>
<table border="1">
<caption>Table 107 &mdash; Sequence container requirements (in addition to container)</caption>
<tr>
<th>Expression</th>
<th>Return type</th>
<th>Assertion&#47;note<br/>pre-&#47;post-condition</th>
</tr>
<tr>
<td colspan="3" align="center">
<code>[&hellip;]</code>
</td>
</tr>
<tr>
<td>
<code>a.assign(n, t)</code>
</td>
<td><code>void</code></td>
<td>
<i>Requires</i>: <code>T</code> shall be <code>CopyInsertable</code> into <code>X</code> and <code>CopyAssignable</code>.<br/>
pre: <code>t</code> is not a reference into <code>a</code>.<br/>
Replaces elements in <code>a</code> with <code>n</code> copies of <code>t</code>.
</td>
</tr>
</table>
</blockquote>
<p>
I looked into the following implementations:
</p>
<ul>
<li><p>
libc++ relies on the precondition.
<p/>
It deallocates first on <code>n &gt; capacity()</code> case,
see <a href="https://github.com/llvm-mirror/libcxx/blob/release_38/include/vector#L1415">here</a>.
</p></li>
<li><p>
libstdc++ doesn't rely on the precondition.
<p/>
It creates temporary <code>vector(n, t)</code> and <code>swap()</code>
on <code>n &gt; capacity()</code> case, see
<a href="https://github.com/gcc-mirror/gcc/blob/gcc_5_3_0_release/libstdc%2B%2B-v3/include/bits/vector.tcc#L223">here</a>.
</p></li>
<li><p>
MSVC relies on the precondition.
<p/>
It unconditionally does <code>clear()</code> and then <code>insert(begin(), n, t)</code>.
I looked into my local "<code>%PROGRAMFILES(X86)%/Microsoft Visual Studio 14.0/VC/include/vector</code>".
</p></li>
</ul>
<p>
One drawback of libstdc++ implementation, I could find so far, is
possibly increased peek memory usage (both old and new buffer exist at
the same time). But, because the same can happen on the most other
modifications, it seems a reasonable trade-off to remove the
precondition to fill the subtle gap. Users who really needs less memory
usage can do <code>clear()</code> and <code>insert()</code> by themselves.
<p/>
I also found that <code>basic_string::assign(n, c)</code> is safe on this point.
At 27.4.3.7.3 <a href="https://wg21.link/string.assign">[string.assign]</a> p17:
</p>
<blockquote>
<pre>
basic_string&amp; assign(size_type n, charT c);
</pre>
<blockquote>
<p>
<i>Effects</i>: Equivalent to <code>assign(basic_string(n, c))</code>.
<p/>
<i>Returns</i>: <code>*this</code>.
</p>
</blockquote>
</blockquote>
<p>
This can be seen as another gap.
<p/>
Looking back on the history, I found that the definition of <code>assign(n, t)</code>
was changed at C++14 for library issue <a href="lwg-defects.html#2209" title="assign() overspecified for sequence containers (Status: C++14)">2209</a><sup><a href="https://cplusplus.github.io/LWG/issue2209" title="Latest snapshot">(i)</a></sup>. There were more restricting 
definitions like this:
</p>
<blockquote>
<pre>
void assign(size_type n, const T&amp; t);
</pre>
<blockquote>
<p>
<i>Effects</i>:
</p>
<blockquote><pre>
erase(begin(), end());
insert(begin(), n, t);
</pre></blockquote>
</blockquote>
</blockquote>
<p>
I think the precondition was probably set to accept this old definition
and is not required inherently. And if the less memory usage was really
intended, the standard is now underspecifying about that.
</p>

<p><i>[2016-05 Issues Telecon]</i></p>

<p>
Howard believes this should be NAD, but we tabled the discussion.
</p>

<strong>Previous resolution [SUPERSEDED]:</strong>
<blockquote class="note">
<p>
This wording is relative to <a href="https://wg21.link/n4582">N4582</a>.
</p>

<ol>
<li><p>In 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a>, edit Table 107 (Sequence container requirements) as indicated:</p>

<blockquote>
<table border="1">
<caption>Table 107 &mdash; Sequence container requirements (in addition to container)</caption>
<tr>
<th>Expression</th>
<th>Return type</th>
<th>Assertion&#47;note<br/>pre-&#47;post-condition</th>
</tr>
<tr>
<td colspan="3" align="center">
<code>[&hellip;]</code>
</td>
</tr>
<tr>
<td>
<code>a.assign(n, t)</code>
</td>
<td><code>void</code></td>
<td>
<i>Requires</i>: <code>T</code> shall be <code>CopyInsertable</code> into <code>X</code> and <code>CopyAssignable</code>.<br/>
<del>pre: <code>t</code> is not a reference into <code>a</code>.</del><br/> 
Replaces elements in <code>a</code> with <code>n</code> copies of <code>t</code>.
</td>
</tr>
</table>
</blockquote>
</li>
</ol>
</blockquote>

<p><i>[2020-04-25, Daniel syncs current wording with recent working draft]</i></p>



<p id="res-2705"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/n4861">N4861</a>.
</p>

<ol>
<li><p>In 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a>, edit Table [tab:container.seq.req] (Sequence container requirements) as indicated:</p>

<blockquote>
<table border="1">
<caption>Table 77 &mdash; Sequence container requirements (in addition to container) [tab:container.seq.req]</caption>
<tr>
<th>Expression</th>
<th>Return type</th>
<th>Assertion&#47;note<br/>pre-&#47;post-condition</th>
</tr>
<tr>
<td colspan="3" align="center">
<code>[&hellip;]</code>
</td>
</tr>
<tr>
<td>
<code>a.assign(n, t)</code>
</td>
<td><code>void</code></td>
<td>
<i>Preconditions</i>: <code>T</code> is <i>Cpp17CopyInsertable</i> into <code>X</code><br/> 
and <i>Cpp17CopyAssignable</i>. <del><code>t</code> is not a reference into <code>a</code>.</del><br/>
<i>Effects:</i> Replaces elements in <code>a</code> with <code>n</code> copies of <code>t</code>.<br/>
Invalidates all references, pointers and iterators referring to the elements of <code>a</code>.<br/> 
For <code>vector</code> and <code>deque</code>, also invalidates the past-the-end iterator.
</td>
</tr>
</table>
</blockquote>
</li>
</ol>





</body>
</html>
