This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++11 status.
Section: 24.6.2 [istream.iterator] Status: C++11 Submitter: Martin Sebor Opened: 2008-05-17 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [istream.iterator].
View all issues with C++11 status.
Discussion:
From message c++std-lib-20003...
The description of istream_iterator
in
24.6.2 [istream.iterator], p. 1 specifies that objects of the
class become the end-of-stream (EOS) iterators under the
following condition (see also issue 788(i) another problem
with this paragraph):
If the end of stream is reached (
operator void*()
on the stream returnsfalse
), the iterator becomes equal to the end-of-stream iterator value.
One possible implementation approach that has been used in practice is
for the iterator to set its in_stream
pointer to 0 when
it reaches the end of the stream, just like the default ctor does on
initialization. The problem with this approach is that
the Effects clause for operator++()
says the
iterator unconditionally extracts the next value from the stream by
evaluating *in_stream >> value
, without checking
for (in_stream == 0)
.
Conformance to the requirement outlined in the Effects clause
can easily be verified in programs by setting eofbit
or failbit
in exceptions()
of the associated
stream and attempting to iterate past the end of the stream: each
past-the-end access should trigger an exception. This suggests that
some other, more elaborate technique might be intended.
Another approach, one that allows operator++()
to attempt
to extract the value even for EOS iterators (just as long
as in_stream
is non-0) is for the iterator to maintain a
flag indicating whether it has reached the end of the stream. This
technique would satisfy the presumed requirement implied by
the Effects clause mentioned above, but it isn't supported by
the exposition-only members of the class (no such flag is shown). This
approach is also found in existing practice.
The inconsistency between existing implementations raises the question
of whether the intent of the specification is that a non-EOS iterator
that has reached the EOS become a non-EOS one again after the
stream's eofbit
flag has been cleared? That is, are the
assertions in the program below expected to pass?
sstream strm ("1 "); istream_iterator eos; istream_iterator it (strm); int i; i = *it++ assert (it == eos); strm.clear (); strm << "2 3 "; assert (it != eos); i = *++it; assert (3 == i);
Or is it intended that once an iterator becomes EOS it stays EOS until the end of its lifetime?
[ San Francisco: ]
We like the direction of the proposed resolution. We're not sure about the wording, and we need more time to reflect on it,
Move to Open. Detlef to rewrite the proposed resolution in such a way that no reference is made to exposition only members of
istream_iterator
.
[ 2009-07 Frankfurt: ]
Move to Ready.
Proposed resolution:
The discussion of this issue on the reflector suggests that the intent
of the standard is for an istreambuf_iterator
that has
reached the EOS to remain in the EOS state until the end of its
lifetime. Implementations that permit EOS iterators to return to a
non-EOS state may only do so as an extension, and only as a result of
calling istream_iterator
member functions on EOS
iterators whose behavior is in this case undefined.
To this end we propose to change 24.6.2 [istream.iterator], p1, as follows:
The result of operator-> on an end-of-stream is not defined. For any other iterator value a
const T*
is returned. Invokingoperator++()
on an end-of-stream iterator is undefined. It is impossible to store things into istream iterators...
Add pre/postconditions to the member function descriptions of istream_iterator
like so:
istream_iterator();Effects: Constructs the end-of-stream iterator.
Postcondition:in_stream == 0
.istream_iterator(istream_type &s);Effects: Initializes
in_stream
with &s. value may be initialized during construction or the first time it is referenced.
Postcondition:in_stream == &s
.istream_iterator(const istream_iterator &x);Effects: Constructs a copy of
x
.
Postcondition:in_stream == x.in_stream
.istream_iterator& operator++();Requires:
in_stream != 0
.
Effects:*in_stream >> value
.istream_iterator& operator++(int);Requires:
in_stream != 0
.
Effects:istream_iterator tmp (*this); *in_stream >> value; return tmp;