<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2122: merge() stability for lists versus forward lists</title>
<meta property="og:title" content="Issue 2122: merge() stability for lists versus forward lists">
<meta property="og:description" content="C++ library issue. Status: C++14">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2122.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="2122"><a href="lwg-defects.html#2122">2122</a>. <code>merge()</code> stability for lists versus forward lists</h3>
<p><b>Section:</b> 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, 23.3.7.6 <a href="https://wg21.link/forward.list.ops">[forward.list.ops]</a> <b>Status:</b> <a href="lwg-active.html#C++14">C++14</a>
 <b>Submitter:</b> Nicolai Josuttis <b>Opened:</b> 2012-01-15 <b>Last modified:</b> 2023-02-07</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all other</b> <a href="lwg-index.html#list.ops">issues</a> in [list.ops].</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>
<code>forward_list::merge()</code> is specified in   [forwardlist.ops], p19 as follows:
</p>
<blockquote><p>
This operation shall be stable: for equivalent elements in the two lists,
the elements from <code>*this</code> shall always precede the elements from <code>x</code>.
</p></blockquote>
<p>
But <code>list::merge()</code> is only specified in 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, p24 as follows:
</p>
<blockquote><p>
<i>Remarks</i>: Stable.
</p></blockquote>
<p>
Note that in general we define "stable" only for algorithms (see 3.60 <a href="https://wg21.link/defns.stable">[defns.stable]</a> and 
16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>) so for member function we should explain it everywhere we use it.
<p/>
Thus for lists we have to add:
</p>
<blockquote><p>
Stable: for equivalent elements in the two lists, the elements from the list always precede the elements
from the argument list.
</p></blockquote>
<p>
This, BTW, was the specification we had with C++03.
<p/>
In addition, I wonder whether we also have some guarantees regarding stability saying that the order 
of equivalent elements of each list merged remains stable (which would be my interpretation of just 
saying "stable", BTW).
<p/>
Thus, I'd expect that for equivalent elements we guarantee that
</p>
<ul>
 <li> we first have all element of <code>*this</code> (in the same order as on entry)</li>
 <li> and then all elements of the passed argument (in the same order as on entry).</li>
</ul>


<p><i>[2012, Kona]</i></p>

<p>
Move to Open.
</p>
<p>
STL says we need to fix up 17.6.5.7 to be stronger, and then the remarks for merge should
just say "Remarks: Stable (see 17.6.5.7)"
</p>
<p>
Assigned to STL for word-smithing.
</p>

<p><i>[
2013-04-14 STL provides rationale and improved wording
]</i></p>


<p>Step 1: Centralize all specifications of stability to 16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>.</p>
<p>Step 2: 3.60 <a href="https://wg21.link/defns.stable">[defns.stable]</a> and 16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a> talk about "algorithms", without mentioning 
"container member functions". There's almost no potential for confusion here, but there's a simple way to increase clarity 
without increasing verbosity: make the container member functions explicitly cite 16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>. For 
consistency, we can also update the non-member functions.</p>
<p>Step 3: Fix the "so obvious, we forgot to say it" bug in 16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>: a "stable" merge of equivalent 
elements A B C D and W X Y Z produces A B C D W X Y Z, never D C B A X W Z Y.</p>
<p>Step 3.1: Say "(preserving their original order)" to be consistent with "the relative order [...] is preserved" in 
16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>'s other bullet points.</p>
<p>Step 4: Copy part of <code>list::merge()</code>'s wording to <code>forward_list::merge()</code>, in order to properly connect 
with 16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>'s "first range" and "second range".</p>

<p><i>[2013-04-18, Bristol]</i></p>


<p>Original wording saved here:</p>
<blockquote class="note">
<p>This wording is relative to the FDIS.</p>

<ol>
<li>
<p>Change 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a> as indicated:</p>

<blockquote><pre>
void                          merge(list&lt;T,Allocator&gt;&amp; x);
void                          merge(list&lt;T,Allocator&gt;&amp;&amp; x);
template &lt;class Compare&gt; void merge(list&lt;T,Allocator&gt;&amp; x, Compare comp);
template &lt;class Compare&gt; void merge(list&lt;T,Allocator&gt;&amp;&amp; x, Compare comp);</pre>
<blockquote><p>
[&hellip;]
<p/>
-24- <i>Remarks</i>: <del>Stable</del><ins>This operation shall be stable: for equivalent elements 
in the two lists, the elements from <code>*this</code> shall always precede the elements from <code>x</code>
and the order of equivalent elements of <code>*this</code> and <code>x</code> remains stable</ins>. If 
<code>(&amp;x != this)</code> the range <code>[x.begin(), x.end())</code> 
is empty after the merge. No elements are copied by this operation. The behavior is undefined if 
<code>this-&gt;get_allocator() != x.get_allocator()</code>.
</p></blockquote></blockquote>
</li>

<li>
<p>Change  [forwardlist.ops] as indicated:</p>

<blockquote><pre>
void merge(forward_list&lt;T,Allocator&gt;&amp; x);
void merge(forward_list&lt;T,Allocator&gt;&amp;&amp; x);
template &lt;class Compare&gt; void merge(forward_list&lt;T,Allocator&gt;&amp; x, Compare comp);
template &lt;class Compare&gt; void merge(forward_list&lt;T,Allocator&gt;&amp;&amp; x, Compare comp);</pre>
<blockquote><p>
[&hellip;]
<p/>
-19- <i>Effects</i>: Merges <code>x</code> into <code>*this</code>. This operation shall be stable: for 
equivalent elements in the two lists, the elements from <code>*this</code> shall always precede the 
elements from <code>x</code> <ins>and the order of equivalent elements of <code>*this</code> and <code>x</code> 
remains stable</ins>. <code>x</code> is empty after the merge. If an exception is thrown other 
than by a comparison there are no effects. Pointers and references to the moved elements of <code>x</code> 
now refer to those same elements but as members of <code>*this</code>. Iterators referring
to the moved elements will continue to refer to their elements, but they now behave as iterators into
<code>*this</code>, not into <code>x</code>.
</p></blockquote></blockquote>
</li>
</ol>
</blockquote>



<p id="res-2122"><b>Proposed resolution:</b></p>
<p>This wording is relative to the N3485.</p>

<ol>
<li><p>Change 16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>/1 as indicated:</p>
<blockquote><p>
When the requirements for an algorithm state that it is “stable” without further elaboration, it means:
<p/>
[&hellip;]
</p>
<ul>
<li>For the <em>merge</em> algorithms, for equivalent elements in the original two ranges, the elements from the
first range <ins>(preserving their original order)</ins> precede the elements from the second range <ins>(preserving 
their original order)</ins>.</li>
</ul>
</blockquote>
</li>

<li><p>Change  [forwardlist.ops] as indicated:</p>
<blockquote>
<pre>
void remove(const T&amp; value);
template &lt;class Predicate&gt; void remove_if(Predicate pred);
</pre>
<blockquote>
<p>
-12- <i>Effects</i>: Erases all the elements in the list referred by a list iterator <code>i</code> for which the following conditions
hold: <code>*i == value</code> (for <code>remove()</code>), <code>pred(*i)</code> is true (for <code>remove_if()</code>). <del>This operation shall be 
stable: the relative order of the elements that are not removed is the same as their relative order in the original
list.</del> Invalidates only the iterators and references to the erased elements.
<p/>
-13- <i>Throws</i>: Nothing unless an exception is thrown by the equality comparison or the predicate.
<p/>
<ins>-??- <i>Remarks</i>: Stable (16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>).</ins>
<p/>
[&hellip;]
</p>
</blockquote>

<pre>
void merge(forward_list&amp; x);
void merge(forward_list&amp;&amp; x);
template &lt;class Compare&gt; void merge(forward_list&amp; x, Compare comp)
template &lt;class Compare&gt; void merge(forward_list&amp;&amp; x, Compare comp)
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-19- <i>Effects</i>: Merges <del><code>x</code> into <code>*this</code></del><ins>the two sorted ranges <code>[begin(), end())</code> 
and <code>[x.begin(), x.end())</code></ins>. <del>This operation shall be stable: for equivalent 
elements in the two lists, the elements from <code>*this</code> shall always precede the elements from <code>x</code>.</del> 
<code>x</code> is empty after the merge. If an exception is thrown other than by a comparison there are no effects. Pointers and 
references to the moved elements of <code>x</code> now refer to those same elements but as members of <code>*this</code>. 
Iterators referring to the moved elements will continue to refer to their elements, but they now behave as iterators into
<code>*this</code>, not into <code>x</code>.
<p/>
-20- <i>Remarks</i>: <ins>Stable (16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>).</ins> The behavior is undefined if 
<code>this-&gt;get_allocator() != x.get_allocator()</code>.
<p/>
[&hellip;]
</p>
</blockquote>
<pre>
void sort();
template &lt;class Compare&gt; void sort(Compare comp);
</pre><blockquote>
<p>
[&hellip;]
<p/>
-23- <i>Effects</i>: Sorts the list according to the <code>operator&lt;</code> or the <code>comp</code> function object. <del>This 
operation shall be stable: the relative order of the equivalent elements is preserved.</del> If an exception is thrown the order
of the elements in <code>*this</code> is unspecified. Does not affect the validity of iterators and references.
<p/>
<ins>-??- <i>Remarks</i>: Stable (16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>).</ins>
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a> as indicated:</p>
<blockquote>
<pre>
void remove(const T&amp; value);
template &lt;class Predicate&gt; void remove_if(Predicate pred);
</pre>
<blockquote>
<p>
[&hellip;]<p/>
-17- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
<p/>
[&hellip;]</p>
</blockquote>

<pre>
void merge(list&amp; x);
void merge(list&amp;&amp; x);
template &lt;class Compare&gt; void merge(list&amp; x, Compare comp)
template &lt;class Compare&gt; void merge(list&amp;&amp; x, Compare comp)
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-24- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>. [&hellip;]
<p/>
[&hellip;]
</p>
</blockquote>
<pre>
void sort();
template &lt;class Compare&gt; void sort(Compare comp);
</pre><blockquote>
<p>
[&hellip;]
<p/>
-30- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
<p/>
[&hellip;]
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 26.7.1 <a href="https://wg21.link/alg.copy">[alg.copy]</a>/12 as indicated:</p>
<blockquote>
<pre>
template&lt;class InputIterator, class OutputIterator, class Predicate&gt;
OutputIterator 
copy_if(InputIterator first, InputIterator last,
        OutputIterator result, Predicate pred);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-12- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 26.7.8 <a href="https://wg21.link/alg.remove">[alg.remove]</a> as indicated:</p>
<blockquote>
<pre>
template&lt;class ForwardIterator, class T&gt;
ForwardIterator 
remove(ForwardIterator first, ForwardIterator last, const T&amp; value);
template&lt;class ForwardIterator, class Predicate&gt;
ForwardIterator 
remove_if(ForwardIterator first, ForwardIterator last, Predicate pred);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-4- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
<p/>
[&hellip;]
</p>
</blockquote>

<pre>
template&lt;class InputIterator, class OutputIterator, class T&gt;
OutputIterator
remove_copy(InputIterator first, InputIterator last,
            OutputIterator result, const T&amp; value);
template&lt;class InputIterator, class OutputIterator, class Predicate&gt;
OutputIterator
remove_copy_if(InputIterator first, InputIterator last,
               OutputIterator result, Predicate pred);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-11- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 26.8.2.2 <a href="https://wg21.link/stable.sort">[stable.sort]</a>/4 as indicated:</p>
<blockquote>
<pre>
template&lt;class RandomAccessIterator&gt;
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
template&lt;class RandomAccessIterator, class Compare&gt;
void stable_sort(RandomAccessIterator first, RandomAccessIterator last,
Compare comp);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-4- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
</p>
</blockquote>
</blockquote>
</li>

<li><p>Change 26.8.6 <a href="https://wg21.link/alg.merge">[alg.merge]</a> as indicated:</p>
<blockquote>
<pre>
template&lt;class InputIterator1, class InputIterator2,
         class OutputIterator&gt;
OutputIterator
merge(InputIterator1 first1, InputIterator1 last1,
      InputIterator2 first2, InputIterator2 last2,
      OutputIterator result);
template&lt;class InputIterator1, class InputIterator2,
         class OutputIterator, class Compare&gt;
OutputIterator
merge(InputIterator1 first1, InputIterator1 last1,
      InputIterator2 first2, InputIterator2 last2,
      OutputIterator result, Compare comp);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-5- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
<p/>
[&hellip;]
</p>
</blockquote>

<pre>
template&lt;class BidirectionalIterator&gt;
void inplace_merge(BidirectionalIterator first,
                   BidirectionalIterator middle,
                   BidirectionalIterator last);
template&lt;class BidirectionalIterator, class Compare&gt;
void inplace_merge(BidirectionalIterator first,
                   BidirectionalIterator middle,
                   BidirectionalIterator last, Compare comp);
</pre>
<blockquote>
<p>
[&hellip;]
<p/>
-9- <i>Remarks</i>: Stable <ins>(16.4.6.8 <a href="https://wg21.link/algorithm.stable">[algorithm.stable]</a>)</ins>.
</p>
</blockquote>
</blockquote>
</li>

</ol>






</body>
</html>
