<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 371: Stability of multiset and multimap member functions</title>
<meta property="og:title" content="Issue 371: Stability of multiset and multimap member functions">
<meta property="og:description" content="C++ library issue. Status: CD1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue371.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#CD1">CD1</a> status.</em></p>
<h3 id="371"><a href="lwg-defects.html#371">371</a>. Stability of multiset and multimap member functions</h3>
<p><b>Section:</b> 23.2 <a href="https://wg21.link/container.requirements">[container.requirements]</a> <b>Status:</b> <a href="lwg-active.html#CD1">CD1</a>
 <b>Submitter:</b> Frank Compagner <b>Opened:</b> 2002-07-20 <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#container.requirements">issues</a> in [container.requirements].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#CD1">CD1</a> status.</p>
<p><b>Discussion:</b></p>
<p>
The requirements for multiset and multimap containers (23.1
[lib.containers.requirements], 23.1.2 [lib.associative.reqmnts],
23.3.2 [lib.multimap] and 23.3.4 [lib.multiset]) make no mention of
the stability of the required (mutating) member functions. It appears
the standard allows these functions to reorder equivalent elements of
the container at will, yet the pervasive red-black tree implementation
appears to provide stable behaviour.
</p>

<p>This is of most concern when considering the behaviour of erase().
A stability requirement would guarantee the correct working of the
following 'idiom' that removes elements based on a certain predicate
function.
</p>

<pre>
  multimap&lt;int, int&gt; m;
  multimap&lt;int, int&gt;::iterator i = m.begin();
  while (i != m.end()) {
      if (pred(i))
          m.erase (i++);
      else
          ++i;
  }
</pre>

<p>
Although clause 23.1.2/8 guarantees that i remains a valid iterator
througout this loop, absence of the stability requirement could
potentially result in elements being skipped. This would make
this code incorrect, and, furthermore, means that there is no way
of erasing these elements without iterating first over the entire
container, and second over the elements to be erased. This would
be unfortunate, and have a negative impact on both performance and
code simplicity.
</p>

<p>
If the stability requirement is intended, it should be made explicit
(probably through an extra paragraph in clause 23.1.2).
</p>
<p>
If it turns out stability cannot be guaranteed, i'd argue that a
remark or footnote is called for (also somewhere in clause 23.1.2) to
warn against relying on stable behaviour (as demonstrated by the code
above).  If most implementations will display stable behaviour, any
problems emerging on an implementation without stable behaviour will
be hard to track down by users. This would also make the need for an
erase_if() member function that much greater.
</p>

<p>This issue is somewhat related to LWG issue <a href="lwg-defects.html#130" title="Return type of container::erase(iterator) differs for associative containers (Status: CD1)">130</a><sup><a href="https://cplusplus.github.io/LWG/issue130" title="Latest snapshot">(i)</a></sup>.</p>



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

<p>Add the following to the end of 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> paragraph 4: 
"For <code>multiset</code> and <code>multimap</code>, <code>insert</code>and <code>erase</code>
  are <i>stable</i>: they preserve the relative ordering of equivalent
  elements.</p> 

<p><i>[Lillehammer: Matt provided wording]</i></p>

<p><i>[Joe Gottman points out that the provided wording does not address
multimap and multiset.  N1780 also addresses this issue and suggests
wording.]</i></p>


<p><i>[Mont Tremblant: Changed set and map to multiset and multimap.]</i></p>




<p><b>Rationale:</b></p>
<p>The LWG agrees that this guarantee is necessary for common user
  idioms to work, and that all existing implementations provide this
  property.  Note that this resolution guarantees stability for
  multimap and multiset, not for all associative containers in
  general.</p>






</body>
</html>
