<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2016: Allocators must be no-throw swappable</title>
<meta property="og:title" content="Issue 2016: Allocators must be no-throw swappable">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2016.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++17">C++17</a> status.</em></p>
<h3 id="2016"><a href="lwg-defects.html#2016">2016</a>. <code>Allocators</code> must be no-throw <i>swappable</i></h3>
<p><b>Section:</b> 16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2010-11-17 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>2
</p>
<p><b>View other</b> <a href="lwg-index-open.html#allocator.requirements">active issues</a> in [allocator.requirements].</p>
<p><b>View all other</b> <a href="lwg-index.html#allocator.requirements">issues</a> in [allocator.requirements].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++17">C++17</a> status.</p>
<p><b>Discussion:</b></p>
<p>
During the Batavia meeting it turned out that there is a definition
hole for types satisfying the <code>Allocators</code> requirements: The problem
became obvious when it was discussed whether all <code>swap</code> functions 
of <code>Containers</code> with internal data handles can be safely tagged
with <code>noexcept</code> or not. While it is correct that the implicit
<code>swap</code> function of an allocator is required to be a no-throw
operation (because move/copy-constructors and assignment operators are
required to be no-throw functions), there are no such requirements
for specialized <code>swap</code> overloads for a particular allocator.
<p/>
But this requirement is essential because the <code>Containers</code> are
required to support <i>swappable</i> <code>Allocators</code>, when the value
<code>allocator_traits&lt;&gt;::propagate_on_container_swap</code> evaluates
to <code>true</code>.
</p>
<p><i>[2011-02-10 Alberto, Daniel, and Pablo collaborated on the proposed wording]</i></p>

<p>
The proposed resolution (based on N3225) attempts to solve the following problems:
</p>
<ol>
<li>Table 44 &mdash; Allocator requirements, expression rows 
<code>X::propagate_on_container_copy_assignment</code>, <code>X::propagate_on_container_move_assignment</code>, and
<code>X::propagate_on_container_swap</code> only describe operations, but no requirements. In fact, if and only
if these compile-time predicates evaluate to <code>true</code>, the <em>additional</em> requirements
<code>CopyAssignable</code>,  no-throw <code>MoveAssignable</code>, and no-throw lvalue <code>Swappable</code>, 
respectively, are imposed on the allocator types.</li>
<li>23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a> p. 9 misses to refer to the correct swap conditions: The current wording does not relate to
16.4.4.3 <a href="https://wg21.link/swappable.requirements">[swappable.requirements]</a> as it should and omits to mention that lvalues shall be swapped. Additional there is one
situation described twice in p. 8 and p. 9 (undefined behaviour unless <code>a.get_allocator() == b.get_allocator()</code>
or <code>allocator_traits&lt;allocator_type&gt;::propagate_on_container_swap::value == true</code>), which should be cleaned up.</li>
</ol>

<p><i>[2011-04-08 Pablo comments]</i></p>

<p>
I'm implementing a version of list now and I actually do find it impossible to write an exception-safe assignment 
operator unless I can assume that allocator assignment does not throw.  (The problem is that I use a sentinel node 
and I need to allocate a new sentinel using the new allocator without destroying the old one -- then swap the 
allocator and sentinel pointer in atomically, without risk of an exception leaving one inconsistent with the other.
<p/>
Please update the proposed resolution to add the nothrow requirement to copy-assignment.
</p>

<p><i>[2014-02-14 Issaquah: Move to Ready]</i></p>

<p>
Fix a couple of grammar issues related to calling <code>swap</code> and move to Ready.
</p>



<p id="res-2016"><b>Proposed resolution:</b></p>
<ol>
<li>
<p>
Adapt the following three rows from Table 44 &mdash; Allocator requirements:
</p>

<blockquote>
<table border="1">
<caption>Table 44 &mdash; Allocator requirements</caption>
<tr>
<th>
Expression
</th>

<th>
Return type
</th>

<th>
Assertion/note<br/>pre-/post-condition
</th>

<th>
Default
</th>

</tr>

<tr>
<td><code>X::propagate_on_container_copy_assignment</code></td>

<td>Identical to or derived from <code>true_type</code><br/>
or <code>false_type</code></td>

<td><code>true_type</code> only if an allocator of type <code>X</code> should be copied<br/> 
when the client container is copy-assigned. <ins>See Note B, below.</ins></td>

<td><code>false_type</code></td>
</tr>

<tr>
<td><code>X::propagate_on_container_move_assignment</code></td>

<td>Identical to or derived from <code>true_type</code><br/>
or <code>false_type</code></td>

<td><code>true_type</code> only if an allocator of type <code>X</code> should be moved<br/>
when the client container is move-assigned. <ins>See Note B, below.</ins></td>

<td><code>false_type</code></td>
</tr>

<tr>
<td><code>X::propagate_on_container_swap</code></td>

<td>Identical to or derived from <code>true_type</code><br/>
or <code>false_type</code></td>

<td><code>true_type</code> only if an allocator of type <code>X</code> should be swapped<br/>
when the client container is swapped. <ins>See Note B, below.</ins></td>

<td><code>false_type</code></td>
</tr>

</table>
</blockquote>


</li>

<li>
<p>Following 16.4.4.6 <a href="https://wg21.link/allocator.requirements">[allocator.requirements]</a> p. 3 insert a new normative paragraph:</p>

<blockquote><p>
<ins>Note B: If <code>X::propagate_on_container_copy_assignment::value</code> is true, <code>X</code> shall 
satisfy the <code>CopyAssignable</code> requirements (Table 39  [copyassignable]) and the copy 
operation shall not throw exceptions. If <code>X::propagate_on_container_move_assignment::value</code> is 
true, <code>X</code> shall satisfy the <code>MoveAssignable</code> requirements (Table 38  [moveassignable]) 
and the move operation shall not throw exceptions. If <code>X::propagate_on_container_swap::value</code> is 
true, lvalues of <code>X</code> shall be swappable (16.4.4.3 <a href="https://wg21.link/swappable.requirements">[swappable.requirements]</a>) and the <code>swap</code> 
operation shall not throw exceptions.</ins>
</p></blockquote>
</li>

<li>
<p>Modify 23.2.2 <a href="https://wg21.link/container.requirements.general">[container.requirements.general]</a> p. 8 and p. 9 as indicated:</p>

<blockquote><p>
8 - [..] The allocator may be replaced only via assignment or <code>swap()</code>. Allocator replacement is 
performed by copy assignment, move assignment, or swapping of the allocator only if 
<code>allocator_traits&lt;allocator_type&gt;::propagate_on_container_copy_assignment::value</code>,
<code>allocator_traits&lt;allocator_type&gt;::propagate_on_container_move_assignment::value</code>, 
or <code>allocator_traits&lt;allocator_type&gt;::propagate_on_container_swap::value</code> is true 
within the implementation of the corresponding container operation. <del>The behavior of a call to 
a container's <code>swap</code> function is undefined unless the objects being swapped have allocators that compare 
equal or <code>allocator_traits&lt;allocator_type&gt;::propagate_on_container_swap::value</code> is true</del>. In all 
container types defined in this Clause, the member <code>get_allocator()</code> returns a copy of the allocator 
used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement.
<p/>
9 - The expression <code>a.swap(b)</code>, for containers <code>a</code> and <code>b</code> of a standard container type 
other than <code>array</code>, shall exchange the values of <code>a</code> and <code>b</code> without invoking any move, 
copy, or swap operations on the individual container elements. <ins>Lvalues of a</ins><del>A</del>ny <code>Compare</code>, 
<code>Pred</code>, or <code>Hash</code> <del>objects</del><ins>types</ins> belonging to <code>a</code> and <code>b</code> shall be swappable 
and shall be exchanged by <del>unqualified calls to non-member</del> <ins>calling</ins> <code>swap</code> 
<ins>as described in 16.4.4.3 <a href="https://wg21.link/swappable.requirements">[swappable.requirements]</a></ins>. If <code>allocator_traits&lt;allocator_type&gt;::propagate_on_container_swap::value</code> 
is <code>true</code>, then <ins>lvalues of <code>allocator_type</code> shall be swappable and</ins> the allocators of <code>a</code> and 
<code>b</code> shall also be exchanged <del>using an unqualified call to non-member</del><ins>by calling</ins>
<code>swap</code> <ins>as described in 16.4.4.3 <a href="https://wg21.link/swappable.requirements">[swappable.requirements]</a></ins>. Otherwise, 
<del>they</del><ins>the allocators</ins> shall not be swapped, and the behavior is undefined unless
<code>a.get_allocator() == b.get_allocator()</code>. Every iterator referring to an element in one container before
the swap shall refer to the same element in the other container after the swap. It is unspecified whether an
iterator with value <code>a.end()</code> before the swap will have value <code>b.end()</code> after the swap.
</p></blockquote>
</li>
</ol>






</body>
</html>
