Level 31
Level 31

Reputation: 403

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?

Upvotes: 10

Views: 1015

Answers (4)

Kerrek SB
Kerrek SB

Reputation: 476970

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.

Upvotes: 11

user2249683
user2249683

Reputation:

Actually the stream iterators are not useful by itself. Having a set of algorithms operating on iterators make them useful.

Upvotes: 2

Zac Howland
Zac Howland

Reputation: 15872

As an example to demonstrate what Kerrek and Jerry have already stated:

Instead of writing something like this:

std::vector<int> vInts;
int n;
while (fin >> n) // where fin is an open ifstream
    vInts.push_back(n);
// ...
for (int i = 0; i < vInts.size(); ++i)
    cout << vInts[i] << endl;

istream_iterator and ostream_iterator allow you to write code that does the same thing in a single line:

copy(istream_iterator<int>(fin), istream_iterator<int>(), ostream_iterator<int>(cout, "\n"));

Which avoids the temporary storage and potential loop-condition bugs (e.g. if you were to write <= instead of <).

Since the standard algorithms use iterators, having iterators for istreams and ostreams allows for usage of streams with many common algorithms.

Upvotes: 1

Jerry Coffin
Jerry Coffin

Reputation: 490098

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.

Upvotes: 5

Related Questions