<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 897: Forward_list issues... Part 2</title>
<meta property="og:title" content="Issue 897: Forward_list issues... Part 2">
<meta property="og:description" content="C++ library issue. Status: Resolved">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue897.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#Resolved">Resolved</a> status.</em></p>
<h3 id="897"><a href="lwg-defects.html#897">897</a>. Forward_list issues... Part 2</h3>
<p><b>Section:</b> 23.3.7.5 <a href="https://wg21.link/forward.list.modifiers">[forward.list.modifiers]</a> <b>Status:</b> <a href="lwg-active.html#Resolved">Resolved</a>
 <b>Submitter:</b> Howard Hinnant <b>Opened:</b> 2008-09-22 <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#forward.list.modifiers">issues</a> in [forward.list.modifiers].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Resolved">Resolved</a> status.</p>
<p><b>Discussion:</b></p>
<p>
This issue was split off from <a href="lwg-closed.html#892" title="Forward_list issues... (Status: NAD Editorial)">892</a><sup><a href="https://cplusplus.github.io/LWG/issue892" title="Latest snapshot">(i)</a></sup> at the request of the LWG.
</p>

<p><i>[
San Francisco:
]</i></p>


<blockquote>
<p>
This issue is more complicated than it looks.
</p>
<p>
paragraph 47: replace each <code>(first, last) with (first, last]</code>
</p>
<p>
add a statement after paragraph 48 that complexity is O(1)
</p>
<p>
remove the complexity statement from the first overload of splice_after
</p>
<p>
We may have the same problems with other modifiers, like erase_after.
Should it require that all iterators in the range (position, last] be
dereferenceable?
</p>
</blockquote>

<p>
There are actually 3 issues here:
</p>

<ol>
<li>
<p>
What value should <code>erase_after</code> return?  With <code>list</code>, code often
looks like:
</p>
<blockquote><pre>
for (auto i = l.begin(); i != l.end();)
{
    // inspect *i and decide if you want to erase it
    // ...
    if (I want to erase *i)
        i = l.erase(i);
    else
        ++i;
}
</pre></blockquote>
<p>
I.e. the iterator returned from <code>erase</code> is useful for setting up the
logic for operating on the next element.  For <code>forward_list</code> this might
look something like:
</p>
<blockquote><pre>
auto i = fl.before_begin();
auto ip1 = i;
for (++ip1; ip1 != fl.end(); ++ip1)
{
    // inspect *(i+1) and decide if you want to erase it
    // ...
    if (I want to erase *(i+1))
        i = fl.erase_after(i);
    else
        ++i;
    ip1 = i;
}
</pre></blockquote>
<p>
In the above example code, it is convenient if <code>erase_after</code> returns
the element <i>prior</i> to the erased element (range) instead of the element
<i>after</i> the erase element (range).
</p>
<p>
Existing practice:
</p>
<ul>
<li>SGI slist returns an iterator referencing the element <i>after</i> the erased range.</li>
<li>CodeWarrior slist returns an iterator referencing the element <i>before</i> the erased range.</li>
</ul>
<p>
There is not a strong technical argument for either solution over the other.
</p>
</li>

<li>
<p>
With all other containers, operations always work on the range
<code>[first, last)</code> and/or <i>prior to</i> the given <code>position</code>.
</p>
<p>
With <code>forward_list</code>, operations sometimes work on the range
<code>(first, last]</code> and/or <i>after</i> the given <code>position</code>.
</p>
<p>
This is simply due to the fact that in order to operate on
<code>*first</code> (with <code>forward_list</code>) one needs access to
<code>*(first-1)</code>.  And that's not practical with
<code>forward_list</code>.  So the operating range needs to start with <code>(first</code>,
not <code>[first</code> (as the current working paper says). 
</p>
<p>
Additionally, if one is interested in  splicing the range <code>(first, last)</code>,
then (with <code>forward_list</code>), one needs practical (constant time) access to
<code>*(last-1)</code> so that one can set the <i>next</i> field in this node to
the proper value.  As this is not possible with <code>forward_list</code>, one must
specify the last element of interest instead of one past the last element of
interest.  The syntax for doing this is to pass <code>(first, last]</code> instead
of <code>(first, last)</code>.
</p>
<p>
With <code>erase_after</code> we have a choice of either erasing the range
<code>(first, last]</code> <em>or</em> <code>(first, last)</code>.  Choosing the latter
enables:
</p>
<blockquote><pre>
x.erase_after(pos, x.end());
</pre></blockquote>

<p>
With the former, the above statement is inconvenient or expensive due to the lack
of constant time access to <code>x.end()-1</code>.  However we could introduce:
</p>

<blockquote><pre>
iterator erase_to_end(const_iterator position);
</pre></blockquote>

<p>
to compensate.
</p>

<p>
The advantage of the former (<code>(first, last]</code>) for <code>erase_after</code>
is a consistency with <code>splice_after</code> which uses <code>(first, last]</code>
as the specified range.  But this either requires the addition of <code>erase_to_end</code>
or giving up such functionality.
</p>

</li>

<li>
As stated in the discussion of <a href="lwg-closed.html#892" title="Forward_list issues... (Status: NAD Editorial)">892</a><sup><a href="https://cplusplus.github.io/LWG/issue892" title="Latest snapshot">(i)</a></sup>, and reienforced by point 2 above,
a <code>splice_after</code> should work on the source range <code>(first, last]</code>
if the operation is to be <i>&#927;</i>(1).  When splicing an entire list <code>x</code> the
algorithm needs <code>(x.before_begin(), x.end()-1]</code>.  Unfortunately <code>x.end()-1</code>
is not available in constant time unless we specify that it must be.  In order to
make <code>x.end()-1</code> available in constant time, the implementation would have
to dedicate a pointer to it.  I believe the design of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2543.htm">N2543</a>
intended a nominal overhead of <code>foward_list</code> of 1 pointer.  Thus splicing
one <i>entire</i> <code>forward_list</code> into another can not be <i>&#927;</i>(1).
</li>
</ol>

<p><i>[
Batavia (2009-05):
]</i></p>

<blockquote>
<p>
We agree with the proposed resolution.
</p>
<p>
Move to Review.
</p>
</blockquote>

<p><i>[
2009-07 Frankfurt
]</i></p>


<blockquote>
<p>
We may need a new issue to correct splice_after, because it may no
longer be correct to accept an rvalues as an argument. Merge may be
affected, too. This might be issue <a href="lwg-defects.html#1133" title="Does N2844 break current specification of list::splice? (Status: C++11)">1133</a><sup><a href="https://cplusplus.github.io/LWG/issue1133" title="Latest snapshot">(i)</a></sup>. (Howard: confirmed)
</p>
<p>
Move this to Ready, but the Requires clause of the second form of
splice_after should say "(first, last)," not "(first, last]" (there are
three occurrences). There was considerable discussion on this. (Howard: fixed)
</p>
<p>
Alan suggested removing the "foward_last&lt;T. Alloc&gt;&amp;&amp; x"
parameter from the second form of splice_after, because it is redundant.
PJP wanted to keep it, because it allows him to check for bad ranges
(i.e. "Granny knots").
</p>
<p>
We prefer to keep <code>x</code>.
</p>
<p>
Beman. Whenever we deviate from the customary half-open range in the
specification, we should add a non-normative comment to the standard
explaining the deviation. This clarifies the intention and spares the
committee much confusion in the future.
</p>
<p>
Alan to write a non-normative comment to explain the use of fully-closed ranges.
</p>
<p>
Move to Ready, with the changes described above. (Howard: awaiting note from Alan)
</p>
</blockquote>

<p><i>[
2009-10 Santa Cruz:
]</i></p>


<blockquote><p>
<del>NAD Editorial</del><ins>Resolved</ins>, addressed by
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2988.pdf">N2988</a>.
</p></blockquote>



<p id="res-897"><b>Proposed resolution:</b></p>
<p>
Wording below assumes issue <a href="lwg-defects.html#878" title="forward_list preconditions (Status: C++11)">878</a><sup><a href="https://cplusplus.github.io/LWG/issue878" title="Latest snapshot">(i)</a></sup> is accepted, but this issue is
independent of that issue.
</p>

<p>
Change  [forwardlist.modifiers]:
</p>

<blockquote>
<pre>
iterator erase_after(const_iterator position);
</pre>
<blockquote>
<p>
<i>Requires:</i> The iterator following <code>position</code> is dereferenceable.
</p>
<p>
<i>Effects:</i> Erases the element pointed to by the iterator following <code>position</code>.
</p>
<p>
<i>Returns:</i> <del>An iterator pointing to the element following the one that was erased, or <code>end()</code> if no such 
element exists</del>
<ins>An iterator equal to <code>position</code></ins>.
</p>
</blockquote>


<pre>
iterator erase_after(const_iterator position, <ins>const_</ins>iterator last);
</pre>
<blockquote>
<p>
<i>Requires:</i> All iterators in the range
<code><del>[</del><ins>(</ins>position,last)</code>
are dereferenceable.
</p>
<p>
<i>Effects:</i> Erases the elements in the range
<code><del>[</del><ins>(</ins>position,last)</code>.
</p>
<p>
<i>Returns:</i>  <ins>An iterator equal to <code>position</code></ins> <del><code>last</code></del>
</p>
</blockquote>
</blockquote>

<p>
Change  [forwardlist.ops]:
</p>

<blockquote>
<pre>
void splice_after(const_iterator position, forward_list&lt;T,Allocator&gt;&amp;&amp; x);
</pre>
<blockquote>
<p>
<i>Requires:</i> <code>position</code> is <code>before_begin()</code> or a
dereferenceable iterator in the range <code>[begin(), end))</code>. <code>&amp;x != this</code>.
</p>
<p>
<i>Effects:</i> Inserts the contents of <code>x</code> after <code>position</code>, and
<code>x</code> becomes empty. 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>
<p>
<i>Throws:</i> Nothing. 
</p>
<p>
<i>Complexity:</i> <del><i>&#927;</i>(1)</del> <ins><i>&#927;</i>(<code>distance(x.begin(), x.end())</code>)</ins>
</p>
</blockquote>

<p>...</p>

<pre>
void splice_after(const_iterator position, forward_list&lt;T,Allocator&gt;&amp;&amp; x, 
                  const_iterator first, const_iterator last);
</pre>
<blockquote>
<p>
<i>Requires:</i> <code>position</code> is <code>before_begin()</code> or a
dereferenceable iterator in the range <code>[begin(), end))</code>.
<code>(first,last)</code> is a valid range in
<code>x</code>, and all iterators in the range
<code>(first,last)</code> are dereferenceable.
<code>position</code> is not an iterator in the range <code>(first,last)</code>.
</p>
<p>
<i>Effects:</i> Inserts elements in the range <code>(first,last)</code>
after <code>position</code> and removes the elements from <code>x</code>.
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>
<p>
<ins><i>Complexity:</i> <i>&#927;</i>(1).</ins>
</p>
</blockquote>

</blockquote>






</body>
</html>
