<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 491: std::list&lt;>::unique incorrectly specified</title>
<meta property="og:title" content="Issue 491: std::list&lt;>::unique incorrectly specified">
<meta property="og:description" content="C++ library issue. Status: NAD">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue491.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#NAD">NAD</a> status.</em></p>
<h3 id="491"><a href="lwg-closed.html#491">491</a>. std::list&lt;>::unique incorrectly specified</h3>
<p><b>Section:</b> 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a> <b>Status:</b> <a href="lwg-active.html#NAD">NAD</a>
 <b>Submitter:</b> Thomas Mang <b>Opened:</b> 2004-12-12 <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#list.ops">issues</a> in [list.ops].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#NAD">NAD</a> status.</p>
<p><b>Discussion:</b></p>
<p>In Section 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraphs 19 to 21 describe the
behavior of the std::list&lt;T, Allocator>::unique operation. However, the
current wording is defective for various reasons.</p>



<p>
1) Analysis of current wording:
</p>

<p>23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 19:</p>

<p>
Current wording says:
"Effects:  Eliminates all but the first element from every consecutive
group of equal elements referred to by the iterator i in the range
[first + 1, last) for which *i == *(i - 1) (for the version of unique
with no argument) or pred(*i, *(i -1)) (for the version of unique with a
predicate argument) holds."</p>

<p>
This sentences makes use of the undefined term "Eliminates". Although it
is, to a certain degree, reasonable to consider the term "eliminate"
synonymous with "erase", using "Erase" in the first place, as the
wording of 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 15 does, would be clearer.</p>

<p>
The range of the elements referred to by iterator i is "[first + 1,
last)". However, neither "first" nor "last" is defined.</p>

<p>
The sentence makes three times use of iterator arithmetic expressions (
"first + 1", "*i == *(i - 1)", "pred(*i, *(i -1))" ) which is not
defined for bidirectional iterator [see DR submitted by Thomas Mang
regarding invalid iterator arithmetic expressions].</p>

<p>
The same problems as pointed out in DR 202 (equivalence relation / order
of arguments for pred()) apply to this paragraph.</p>

<p>
23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 20:
</p>

<p>
Current wording says:
"Throws: Nothing unless an exception in thrown by *i == *(i-1) or
pred(*i, *(i - 1))"</p>

<p>
The sentence makes two times use of invalid iterator arithmetic
expressions ( "*i == *(i - 1)", "pred(*i, *(i -1))" ).
</p>
<p>
[Note: Minor typos: "in" / missing dot at end of sentence.]
</p>

<p>
23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 21:</p>

<p>
Current wording says:
"Complexity: If the range (last - first) is not empty, exactly (last -
first) - 1 applications of the corresponding predicate, otherwise no
application of the predicate.</p>

<p>
See DR 315 regarding "(last - first)" not yielding a range.</p>

<p>
Invalid iterator arithmetic expression "(last - first) - 1" left .</p>


<p>2) Description of intended behavior:</p>

<p>
For the rest of this Defect Report, it is assumed that "eliminate" is
supposed to be synonymous to "erase", that "first" is equivalent to an
iterator obtained by a call to begin(), "last" is equivalent to an
iterator obtained by a call to end(), and that all invalid iterator
arithmetic expressions are resolved as described in DR submitted by
Thomas Mang regarding invalid iterator arithmetic expressions.</p>

<p>
Furthermore, the resolutions of DR 202 are considered regarding
equivalence relation and order of arguments for a call to pred.</p>

<p>
All implementations known to the author of this Defect Report comply
with these assumptions, apart from the impact of the alternative
resolution of DR 202. Except for the changes implied by the resolutions
of DR 202, no impact on current code is expected.</p>

<p>
3) Proposed fixes:</p>

<p>
Change 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 19 to:</p>

<p>
"Effect: Erases all but the first element from every consecutive group
of elements, referred to by the iterator i in the range [begin(),
end()), for which the following conditions hold: *(i-1) == *i (for the
version of unique with no argument) or pred(*(i-1), *i) != false (for
the version of unique with a predicate argument)."</p>

<p>
Comments to the new wording:</p>

<p>
a) The new wording was influenced by DR 202 and the resolutions
presented there. If DR 202 is resolved in another way, the proposed
wording need also additional review.
b) "Erases" refers in the author's opinion unambiguously to the member
function "erase". In case there is doubt this might not be unamgibuous,
a direct reference to the member function "erase" is suggested [Note:
This would also imply a change of 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph
15.].
c) The expression "(i - 1)" was left, but is expected that DR submitted
by Thomas Mang regarding invalid iterator arithmetic expressions will
take this into account.
d) The wording "(for the version of unique with no argument)" and "(for
the version of unique with a predicate argument)" was kept consciously
for clarity.
e) "begin()" substitutes "first", and "end()" substitutes "last". The
range need adjustment from "[first + 1, last)" to "[begin(), end())" to
ensure a valid range in case of an empty list.
f) If it is considered that the wording is unclear whether it declares
the element of a group which consists of only a single element
implicitly to be the first element of this group [Note: Such an
interpretation could eventually arise especially in case size() == 1] ,
the following additional sentence is proposed: "If such a group of
elements consists of only a single element, this element is also
considered the first element."</p>

<p>
Change 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 20 to:</p>

<p>
"Throws: Nothing unless an exception is thrown by *(i-1) == *i or
pred(*(i-1), *i)."</p>

<p>
Comments to the new wording:</p>

<p>
a) The wording regarding the conditions is identical to proposed
23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 19. If 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>,
paragraph 19 is resolved in another way, the proposed wording need also
additional review.
b) The expression "(i - 1)" was left, but is expected that DR submitted
by Thomas Mang regarding invalid iterator arithmetic expressions will
take this into account.
c) Typos fixed.</p>

<p>
Change 23.3.11.5 <a href="https://wg21.link/list.ops">[list.ops]</a>, paragraph 21 to:</p>

<p>
"Complexity: If empty() == false, exactly size() - 1 applications of the
corresponding predicate, otherwise no applications of the corresponding
predicate."</p>

<p>
Comments to the new wording:</p>

<p>
a) The new wording is supposed to also replace the proposed resolution
of DR 315, which suffers from the problem of undefined "first" / "last".
</p>

<p>
5) References to other DRs:</p>

<p>See DR 202.
See DR 239.
See DR 315.
See DR submitted by Thomas Mang regarding invalid iterator arithmetic
expressions.</p>



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


<p><b>Rationale:</b></p>
<p>"All implementations known to the author of this Defect Report
comply with these assumption", and "no impact on current code is
expected", i.e. there is no evidence of real-world confusion or
harm.</p>





</body>
</html>
