Confused about using 'std :: istreambuf_iterator'

The following is an example of cppreference.com ,

The Code is: #include <vector> #include <sstream> #include <iostream> #include <iterator> int main() { // typical use case: an input stream represented as a pair of iterators std::istringstream in("Hello, world"); std::vector<char> v( (std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>() ); std::cout << "v has " << v.size() << " bytes. "; v.push_back('\0'); std::cout << "it holds \"" << &v[0] << "\"\n"; // demonstration of the single-pass nature 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'; } 

I have two questions:

  • Can someone clarify the code std::vector<char> v( (std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>() ); , I don’t quite understand what he is doing ... and why we can print the string "Hello, world" just using cout<<&v[0]
  • Why does the apptent value for i2 jump beyond "a" to "c"? can someone explain the mechanisms of this?

Thank you very much!

+6
source share
2 answers

Can someone clarify the code ...

std::vector<T> has a constructor that takes two iterators on <T> - one for the start and one for the end of the range.

This constructor makes an iterator of the input stream from the input stream in :

 std::istreambuf_iterator<char>(in) 

You can access your items forward until you reach the end of the stream. Once you reach the end of the stream, the iterator becomes equivalent to the iterator created using the default constructor:

 std::istreambuf_iterator<char>() 

Therefore, passing this pair of iterators builds a vector<T> from data read from the input stream. All flow will be consumed.

Why does the value of apptent *i2 go from "a" to "c" ?

Both iterators are read from the same stream. When you increment the first iterator, it consumes 'b' from the underlying thread. Meanwhile, i2 refers to the first symbol of the stream that it received without moving at the time it was constructed.

As soon as you increment i2 , it requests a stream for the next character. The character 'b' already consumed, so the next character is 'c' .

Finally, the code pulls a little trick that you might have missed: it pushes the null terminator in vector<char> to be able to print the vector using const char* operator <<(...) overload.

+10
source

The default istreambuf_iterator is basically an end-of-file iterator, i.e. another iterator will only be compared with it when it reaches the end of the file.

Therefore, the code:

 std::vector<char> v( (std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>() ); 

... reads char from in until the first iterator is incremented to equal the second iterator, which will happen when (and only when) the first iterator reaches the end of the file (stringstream, in this case). In short, it copies the entire contents of a file to a vector.

The printed part of "hello world" is a bit simpler: ostream has an operator<< overload for char * , which assumes that char * points to a C-style string, so it should print the entire line that pointed to. Since they did push_back to add the string '\0' to the string, this makes it a string of type C.

The second part demonstrates that although you have two iterators in a stream, you still only have one stream and one read position in that stream. At the same time, each iterator contains a copy of the last element that it reads from the stream.

Therefore, at any time, when you increase either an iterator (or any iterator in one thread), it increases the current reading position. So, you start with i1 and i2 , indicating the beginning of the stream. Then you increase i1 . This increases the reading position and reads b in i1 , so when you look for i1 , this is what you get. When you increment i2 , it moves the read position again and reads c in i2 , so dereferencing i2 will give c .

In short, using two (or more) iterators does not change the nature of the stream - every time you increment any iterator in the same stream that reads the next element from this stream - and the "next element" is always determined by the stream itself, based on its one read position.

+2
source

Source: https://habr.com/ru/post/979410/


All Articles