Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do iostream iterators work?

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?

like image 812
Level 31 Avatar asked Jan 02 '14 18:01

Level 31


2 Answers

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.

like image 78
Kerrek SB Avatar answered Oct 03 '22 10:10

Kerrek SB


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.

like image 21
Jerry Coffin Avatar answered Oct 03 '22 08:10

Jerry Coffin