From the Standard Template Library I came to know about the istream
and ostream
iterators. I can't understand how they work.
I also don't understand why they are used. Why are they useful?
Stream iterators provide an iterator interface to the formatted extraction/insertion operations of iostreams. For example, consider the following:
std::vector<int> v;
for (int n; std::cin >> n; )
v.push_back(n);
This is equivalent to:
std::vector<int> v(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>{});
Advancing the iterator performs one exraction, akin to std::cin >> n
; if the extraction fails, the iterator assumes the singular state, which is also the state of the default-constructed iterator.
By their very nature, these stream iterators are single-pass, i.e. the weakest kind of iterator: You can only visit each element in the "range" once, and never go back; and two non-end iterators built from the same stream compare equal although that does not have any meaning regarding the dereferenced value. (But note that there's a curious lack of specificity as to whether the first extraction is ever attempted if you don't dereference the iterator ever.)
Just for completeness, output stream iterators can be used similarly to turn a stream into a "container", useful for algorithms that work with iterators:
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, "\n"));
Ouput stream iterators perform their work when assigned to; the other operations are no-ops.
Interestingly enough, there isn't a stream iterator that wraps getline
; people often write one themselves, because iterator interfaces are useful in many ways.
Stream iterators allow you to use a stream as a source or destination for something like an algorithm that expects to use an input or output iterator.
They're used primarily to give a uniform interface to a basic capability, so you don't need (for one example) to create intermediate results in some collection in memory, then copy your data from there to an output file (and likewise with inputs).
As far as how they work, an istream_iterator normally stores one T object internally. When you create the iterator, it reads (or tries to) one T from the file with stream >> value;
. operator *
gives you access to that value. operator++
reads the next value.
Likewise, an ostream_iterator writes an item to the file when you assign to it. Since the stream advances automatically, operator++
normally doesn't really do anything (except return a reference to the iterator). If you really want to delve into the details (such as they are), you could take a look at the infix_ostream_iterator
I posted some time ago.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With