I have an istream
and need to copy the content between two delimiters to a std::string
.
I can find the delimiters' streampos
, but when trying to use istream_iterator<char>
to iterate over the section of the stream, it does not work. Here's what I tried:
#include <iostream>
#include <sstream>
#include <iterator>
std::string copyToString( std::istream& is )
{
is >> std::ws;
auto someLength {10};
std::istream_iterator<char> beg {is};
is.seekg( someLength, std::ios::cur );
//std::istream_iterator<char> end { is };
std::istream_iterator<char> end { std::next(beg, someLength) };
return std::string{ beg, end };
}
int main()
{
std::stringstream ss;
ss.str( " { my string content }" );
std::cout << "\"" << copyToString( ss ) << "\"\n";
return 0;
}
I expected the output to be 10 chars long, but it's just "{"
. If I uncomment the line std::istream_iterator<char> end { is };
and comment out the next one, the output is just ""
.
What am I missing? Can I not use iterators like that?
I am aware that I could create a char[]
as a buffer, copy it to that, etc., but that seems much less straightforward.
std::istream_iterator
is an input iterator. Input iterators are single pass and are invalidated when copies thereof are incremented. When you do std::next(beg, someLength)
, you read someLength
characters. Then beg
is invalidated.
Moreover, std::istream_iterator
is not intended to be counted. It is designed to be compared to a default constructed iterator, because of the way stream errors are handled. If you attempt count them, then they will sometimes read one more time, depending on how the algorithm is implemented.
If you want to read n
characters from an input stream, just use read
. If you want to skip spaces, then just write a loop. If you want to use std::istream_iterator
in an unintended way, then your code will fail unpredictably.