<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2252: Strong guarantee on vector::push_back() still broken with C++11?</title>
<meta property="og:title" content="Issue 2252: Strong guarantee on vector::push_back() still broken with C++11?">
<meta property="og:description" content="C++ library issue. Status: C++14">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2252.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++14">C++14</a> status.</em></p>
<h3 id="2252"><a href="lwg-defects.html#2252">2252</a>. Strong guarantee on <code>vector::push_back()</code> still broken with C++11?</h3>
<p><b>Section:</b> 23.3.13.5 <a href="https://wg21.link/vector.modifiers">[vector.modifiers]</a> <b>Status:</b> <a href="lwg-active.html#C++14">C++14</a>
 <b>Submitter:</b> Nicolai Josuttis <b>Opened:</b> 2013-04-21 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#vector.modifiers">issues</a> in [vector.modifiers].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++14">C++14</a> status.</p>
<p><b>Discussion:</b></p>

<p>
According to my understanding, the strong guarantee of <code>push_back()</code> led to the introduction of <code>noexcept</code> 
and to the typical implementation that vectors usually copy their elements on reallocation unless the move operations of 
their element type guarantees not to throw.
<p/>
However, if I read the standard correctly, we still don't give the strong guarantee any more:
Yes, 23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a>/10 specifies:
</p>
<blockquote>
<p>
Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.3.4, and 23.3.6.5) all container types defined in this
Clause meet the following additional requirements:
</p>
<ul>
<li>[&hellip;]</li>
<li>if an exception is thrown by a <code>push_back()</code> or <code>push_front()</code> function, that function has no effects.</li>
</ul>
</blockquote>
<p>
However, 23.3.13.5 <a href="https://wg21.link/vector.modifiers">[vector.modifiers]</a> specifies for vector modifiers, <em>including</em> <code>push_back()</code>:
</p>
<blockquote>
<p>
If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move 
assignment operator of <code>T</code> or by any <code>InputIterator</code> operation there are no effects. If an exception 
is thrown by the move constructor of a non-<code>CopyInsertable</code> <code>T</code>, the effects are unspecified.
</p>
</blockquote>
<p>
I would interpret this as an "otherwise specified" behavior for <code>push_back()</code>, saying that the strong guarantee 
is only given if constructors and assignments do not throw. 
<p/>
That means, the strong guarantee of C++03 is broken with C++11.
<p/>
In addition to all that 23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a> p10 b2 doesn't mention the corresponding functions
<code>emplace_back()</code> and <code>emplace_front()</code>. These are similar single-element additions and should provide the same
strong guarantee.
<p/>
Daniel adds:
<p/>
It seems the error came in when <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf">N2350</a>
and <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2345.pdf">N2345</a> became accepted and where 
integrated into the working draft <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2369.pdf">N2369</a>.
The merge resulted in a form that changed the previous meaning and as far as I understand it, this effect was not intended.
</p>

<p><i>[2013-09-16, Nico provides concrete wording]</i></p>


<p><i>[2013-09-26, Nico improves wording]</i></p>


<p>
The new proposed resolution is driven as follows:
</p>
<ul>
 <li> <p>In the container requirements section, there shall be general statements that single element insertions
      and <code>push_back()</code>, <code>pop_back</code>, <code>emplace_front()</code>, and <code>emplace_back()</code> have no effect
      on any exception.
      <p/>
      That is: we extend the first two statements by adding <code>emplace_front()</code> and <code>emplace_back()</code>, which
      are missing.
	  </p>
</li>
 <li> <p>Formulate only the exceptions from that (or where other general statements might
      lead to the impression, that the blanket statement no longer applies):</p>
      <ul>
       <li> <p>remove the statement in <code>list::push_back()</code> saying again that exceptions have to effect.</p></li>
       <li> <p>Clarify that all single-element insertions at either end of a <code>deque</code> have the strong guarantee.</p> </li>
       <li> <p>Clarify that all single-element insertions at the end of a <code>vector</code> have the strong guarantee.</p></li>
      </ul> 
</li>
</ul>




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

<p>This wording is relative to N3691.</p>

<ol>
<li><p>Edit 23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a> p10 b2 as indicated:</p>

<ul>
<li><p>
if an exception is thrown by an <code>insert()</code> or <code>emplace()</code> function while inserting a single element, that
function has no effects.
</p></li>
<li><p>
if an exception is thrown by a <code>push_back()</code> <del>or</del><ins>,</ins> <code>push_front()</code><ins>, <code>emplace_back()</code>, or 
<code>emplace_front()</code></ins> function, that function has no effects.
</p></li>
</ul>

</li>

<li><p>Edit 23.3.5.4 <a href="https://wg21.link/deque.modifiers">[deque.modifiers]</a> as indicated:</p>

<blockquote>
<pre>iterator insert(const_iterator position, const T&amp; x);
iterator insert(const_iterator position, T&amp;&amp; x);
iterator insert(const_iterator position, size_type n, const T&amp; x);
template &lt;class InputIterator&gt;
  iterator insert(const_iterator position,
                  InputIterator first, InputIterator last);
iterator insert(const_iterator position, initializer_list&lt;T&gt;);
template &lt;class... Args&gt; void emplace_front(Args&amp;&amp;... args);
template &lt;class... Args&gt; void emplace_back(Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator emplace(const_iterator position, Args&amp;&amp;... args);
void push_front(const T&amp; x);
void push_front(T&amp;&amp; x);
void push_back(const T&amp; x);
void push_back(T&amp;&amp; x);
</pre>
<blockquote>
<p>
-1- <i>Effects:</i> An insertion in the middle of the deque invalidates all the iterators and references to elements
of the deque. An insertion at either end of the deque invalidates all the iterators to the deque, but has
no effect on the validity of references to elements of the deque.
</p><p>
-2- <i>Remarks:</i> 
If an exception is thrown other than by the copy constructor, move constructor, assignment
operator, or move assignment operator of <code>T</code> there are no effects.
<ins>
If an exception is thrown while inserting a single element at either end, there are no effects.
</ins>
<del>If</del><ins>Otherwise, if</ins> an exception is thrown by the move
constructor of a non-<code>CopyInsertable</code> <code>T</code>, the effects are unspecified.
</p><p>
-3- <i>Complexity:</i> The complexity is linear in the number of elements inserted plus the lesser of the distances
to the beginning and end of the deque. Inserting a single element either at the beginning or end of a
deque always takes constant time and causes a single call to a constructor of <code>T</code>.
</p>
</blockquote></blockquote>
</li>

<li><p>Edit 23.3.13.5 <a href="https://wg21.link/vector.modifiers">[vector.modifiers]</a> as indicated:</p>

<blockquote>
<pre>iterator insert(const_iterator position, const T&amp; x);
iterator insert(const_iterator position, T&amp;&amp; x);
iterator insert(const_iterator position, size_type n, const T&amp; x);
template &lt;class InputIterator&gt;
  iterator insert(const_iterator position, InputIterator first, InputIterator last);
iterator insert(const_iterator position, initializer_list&lt;T&gt;);
template &lt;class... Args&gt; void emplace_back(Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator emplace(const_iterator position, Args&amp;&amp;... args);
void push_back(const T&amp; x);
void push_back(T&amp;&amp; x);
</pre>
<blockquote>
<p>
-1- <i>Remarks:</i> Causes reallocation if the new size is greater than the old capacity. If no reallocation happens,
all the iterators and references before the insertion point remain valid.
If an exception is thrown other
than by the copy constructor, move constructor, assignment operator, or move assignment operator
of <code>T</code> or by any <code>InputIterator</code> operation there are no effects.
<ins>
If an exception is thrown while inserting a single element at the end and <code>T</code> is <code>CopyInsertable</code>
or <code>is_nothrow_move_constructible&lt;T&gt;::value</code> is <code>true</code>, there are no effects.
</ins>
<del>If</del><ins>Otherwise, if</ins> an exception is thrown by the move
constructor of a non-<code>CopyInsertable</code> <code>T</code>, the effects are unspecified.
</p><p>
-2- <i>Complexity:</i> The complexity is linear in the number of elements inserted plus the distance to the end
of the vector.
</p>
</blockquote></blockquote>
</li>
</ol>






</body>
</html>
