How can I declare a istream_iterator on cin without putting the system in reading mode?

Hi,

I have a simple code which is behaving strangely:

1
2
3
istream_iterator<int> it{cin};  // meant to declare an iterator, not to start 
                                // reading from console (standard input that is)
istream_iterator<int> it_end;


It starts reading even before it_end is declared!

Regards,
Juan Dent
Seems to be how it's supposed to work.

C++17 ยง27.6.1/1
The class template istream_iterator is an input iterator (27.2.3) that reads (using operator>>) successive elements from the input stream for which it was constructed. After it is constructed, and every time ++ is used, the iterator reads and stores a value of T. If the iterator fails to read and store a value of T (fail() on the stream returns true), the iterator becomes equal to the end-of-stream iterator value. The constructor with no arguments istream_iterator() always constructs an end-of-stream input iterator object, which is the only legitimate iterator to be used for the end condition. The result of operator* on an end-of-stream iterator is not defined. For any other iterator value a const T& is returned. The result of operator-> on an end-of-stream iterator is not defined. For any other iterator value a const T* is returned. The behavior of a program that applies operator++() to an end-of-stream iterator is undefined. It is impossible to store things into istream iterators. The type T shall meet the DefaultConstructible, CopyConstructible, and CopyAssignable requirements.



The "after" somewhat confuses me. Should that not be "during construction"?
Now that you mention it, "after" does make it sound like it somehow reads the first value after the constructor call has completed. For the constructor it says "value may be initialized during construction or the first time it is referenced" where value refers to the value that operator* returns a reference to, so the intention seems to be to allow the implementation to decide if it should read the first value in the constructor or wait until later. This seems to be how cppreference.com interprets it. But strictly speaking, the only way to satisfy both these sentences seems to be by not doing it in the constructor so I guess one could argue that the behaviour that Juan describes is non-conformant.
as cppreference puts it https://en.cppreference.com/w/cpp/iterator/istream_iterator

The first object may be read when the iterator is constructed or when the first dereferencing is done. Otherwise, dereferencing only returns a copy of the most recently read object.

I think there is at least one implementation for either option (read in constructor and read in the first dereference)
Last edited on
cppreference.com uses the word "dereferencing" and is clearly referring to the * and -> operators of the istream_iterator.

The standard on the other hand uses the word "referenced" : value may be initialized [...] the first time it is referenced. At first I thought they were saying the same thing as cppreference.com but what got me thinking was that I couldn't understand what was supposed to happen if you used ++ before the first value had been read. Then I realized that it seems to be referring to value (the exposition variable), and that referenced probably just means when it's being accessed, no matter if it's a read or write. If my understanding is correct this means that using ++ should actually read two values if the first value has not been read before.
Last edited on
I do think the behavior I describe is non-conformant and it is a new behavior of the current Visual Studio 2017 latest version 15.6.7. As far as I remember it did not behave like this before.
How does it work in linux or MacOS?

Both libstdc++ (GCC) and libc++ (Clang) reads the first value in the constructor.
actually that "After it is constructed" wording is indeed controversial, see

* LWG 245 "Which operations on istream_iterator trigger input operations?" from all the way back in 2000: http://cplusplus.github.io/LWG/lwg-closed.html#245 (which reaffirms " the stream is read every time operator++ is called, and it is also read either when the iterator is constructed or when operator* is called for the first time.")

* paper p0738 "I Stream, You Stream, We All Stream for istream_iterator" from 2017 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0738r0.html which argues that the constructor must read, otherwise input_iterator is not implementable (the paper was up in Abq meeting, but it seems LWG didn't get the time to look at it)

edited cppreference to make a note of this.
Last edited on
Topic archived. No new replies allowed.