Search code examples
c++iostreamiterator

Advancing multiple iterators into the same stringstream


Please check out this code snippet

  std::istringstream s("abc");
  std::istreambuf_iterator<char> i1(s), i2(s);
  std::cout<< "i1 returns "<<*i1<<'\n'
           << "i2 returns "<<*i2<<'\n';
  ++i1;
  std::cout<<"after incrementing i1, but not i2\n"
           <<"i1 returns "<<*i1<<'\n'
           <<"i2 returns "<<*i2<<'\n';
  ++i2; // this makes the apparent value of *i2 to jump from 'a' to 'c'
  std::cout << "after incrementing i2, but not i1\n"
            << "i1 returns " << *i1 << '\n'
            << "i2 returns " << *i2 << '\n';

and i got the output like

a
a

b
b

c
c

which is totally different from what I expected, because i1 & i2 are two different iterators.

Anyone do me a favor?


Solution

  • From cppreference:

    std::istreambuf_iterator is a single-pass input iterator that reads successive characters from the std::basic_streambuf object for which it was constructed.

    The important part here is the single-pass characteristics: once a value has been read, you cannot go back and read it again. Recall that you can use std::istreambuf_iterator for std::cin for example. If you read from std::cin in your program, this means you might interactively type in characters - there is no going back (you have to save the bytes in a std::string or similar to achieve that).

    Now when creating multiple iterators that refer to the identical stream object, advancing one means reading a character - which is seen by all iterators. This is due to the single-pass nature of the iterator, see also the documentation for operator*:

    Reads a single character by calling sbuf_->sgetc() where sbuf_ is the stored pointer to the stream buffer.

    Clearly, all iterator instances share the state that is used by the dereferencing operator.