<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 198: Validity of pointers and references unspecified after iterator destruction</title>
<meta property="og:title" content="Issue 198: Validity of pointers and references unspecified after iterator destruction">
<meta property="og:description" content="C++ library issue. Status: CD1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue198.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="198"><a href="lwg-defects.html#198">198</a>. Validity of pointers and references unspecified after iterator destruction</h3>
<p><b>Section:</b> 24.3.4 <a href="https://wg21.link/iterator.concepts">[iterator.concepts]</a> <b>Status:</b> <a href="lwg-active.html#CD1">CD1</a>
 <b>Submitter:</b> Beman Dawes <b>Opened:</b> 1999-11-03 <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#iterator.concepts">issues</a> in [iterator.concepts].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#CD1">CD1</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Is a pointer or reference obtained from an iterator still valid after
destruction of the iterator?
</p>
<p>
Is a pointer or reference obtained from an iterator still valid after the value
of the iterator changes?
</p>
<blockquote>
<pre>
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;iterator&gt;

int main()
{
    typedef std::vector&lt;int&gt; vec_t;
    vec_t v;
    v.push_back( 1 );

    // Is a pointer or reference obtained from an iterator still
    // valid after destruction of the iterator?
    int * p = &amp;*v.begin();
    std::cout &lt;&lt; *p &lt;&lt; '\n';  // OK?

    // Is a pointer or reference obtained from an iterator still
    // valid after the value of the iterator changes?
    vec_t::iterator iter( v.begin() );
    p = &amp;*iter++;
    std::cout &lt;&lt; *p &lt;&lt; '\n';  // OK?

    return 0;
}
</pre>
</blockquote>

<p>The standard doesn't appear to directly address these
questions. The standard needs to be clarified. At least two real-world
cases have been reported where library implementors wasted
considerable effort because of the lack of clarity in the
standard. The question is important because requiring pointers and
references to remain valid has the effect for practical purposes of
prohibiting iterators from pointing to cached rather than actual
elements of containers.</p>

<p>The standard itself assumes that pointers and references obtained
from an iterator are still valid after iterator destruction or
change. The definition of reverse_iterator::operator*(), 24.5.1.5 <a href="https://wg21.link/reverse.iter.conv">[reverse.iter.conv]</a>, which returns a reference, defines
effects:</p>

<blockquote>
  <pre>Iterator tmp = current;
return *--tmp;</pre>
</blockquote>
<p>The definition of reverse_iterator::operator-&gt;(),  [reverse.iter.op.star], which returns a pointer, defines effects:</p>
<blockquote>
  <pre>return &amp;(operator*());</pre>
</blockquote>

<p>Because the standard itself assumes pointers and references remain
valid after iterator destruction or change, the standard should say so
explicitly. This will also reduce the chance of user code breaking
unexpectedly when porting to a different standard library
implementation.</p>


<p id="res-198"><b>Proposed resolution:</b></p>
<p>Add a new paragraph to 24.3.4 <a href="https://wg21.link/iterator.concepts">[iterator.concepts]</a>:</p>
<blockquote><p>
Destruction of an iterator may invalidate pointers and references
previously obtained from that iterator.
</p></blockquote>

<p>Replace paragraph 1 of 24.5.1.5 <a href="https://wg21.link/reverse.iter.conv">[reverse.iter.conv]</a> with:</p>

<blockquote>
<p><b>Effects:</b></p>
<pre>
  this->tmp = current;
  --this->tmp;
  return *this->tmp;
</pre>

<p>
[<i>Note:</i> This operation must use an auxiliary member variable,
rather than a temporary variable, to avoid returning a reference that
persists beyond the lifetime of its associated iterator.  (See
24.3.4 <a href="https://wg21.link/iterator.concepts">[iterator.concepts]</a>.)  The name of this member variable is shown for
exposition only.  <i>--end note</i>]
</p>
</blockquote>

<p><i>[Post-Tokyo: The issue has been reformulated purely
in terms of iterators.]</i></p>


<p><i>[Pre-Toronto: Steve Cleary pointed out the no-invalidation
assumption by reverse_iterator. The issue and proposed resolution was
reformulated yet again to reflect this reality.]</i></p>


<p><i>[Copenhagen: Steve Cleary pointed out that reverse_iterator
assumes its underlying iterator has persistent pointers and
references.  Andy Koenig pointed out that it is possible to rewrite
reverse_iterator so that it no longer makes such an assupmption.
However, this issue is related to issue <a href="lwg-closed.html#299" title="Incorrect return types for iterator dereference (Status: NAD Editorial)">299</a><sup><a href="https://cplusplus.github.io/LWG/issue299" title="Latest snapshot">(i)</a></sup>.  If we
decide it is intentional that <code>p[n]</code> may return by value
instead of reference when <code>p</code> is a Random Access Iterator,
other changes in reverse_iterator will be necessary.]</i></p>



<p><b>Rationale:</b></p>
<p>This issue has been discussed extensively.  Note that it is
<i>not</i> an issue about the behavior of predefined iterators.  It is
asking whether or not user-defined iterators are permitted to have
transient pointers and references.  Several people presented examples
of useful user-defined iterators that have such a property; examples
include a B-tree iterator, and an "iota iterator" that doesn't point
to memory.  Library implementors already seem to be able to cope with
such iterators: they take pains to avoid forming references to memory
that gets iterated past.  The only place where this is a problem is
<code>reverse_iterator</code>, so this issue changes
<code>reverse_iterator</code> to make it work.</p>

<p>This resolution does not weaken any guarantees provided by
predefined iterators like <code>list&lt;int&gt;::iterator</code>.
Clause 23 should be reviewed to make sure that guarantees for
predefined iterators are as strong as users expect.</p>






</body>
</html>
