Why does std::istream::seekg()
affect the behavior of std::istreambuf_iterator
?
I carefully read the introduction about std::istreambuf_iterator
on cppreference, but there is no direct answer for this matter.
Here is the code snippet:
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
int main()
{
//with seekg to the end
{
std::cout << "#1 with seekg" << std::endl;
std::istringstream in{"Hello, world"};
in.seekg(std::istream::end);
std::istreambuf_iterator<char> it{in}, end;
std::string ss{it, end};
std::cout << ss << std::endl;
}
//without seekg
{
std::cout << "#2 without seekg" << std::endl;
std::istringstream in{"Hello, world"};
std::istreambuf_iterator<char> it{in}, end;
std::string ss{it, end};
std::cout << ss << std::endl;
}
//seekg to end and then to begin
{
std::cout << "#3 seekg to end and then to begin" << std::endl;
std::istringstream in{"Hello, world"};
in.seekg(std::istream::end);
std::streampos pos = in.tellg();
std::cout << "len:" << static_cast<long long>(pos) << std::endl;
in.seekg(std::istream::beg);
std::istreambuf_iterator<char> it{in}, end;
std::string ss{it, end};
std::cout << ss << std::endl;
}
}
Here is the output:
#1 with seekg
llo, world
#2 without seekg
Hello, world
#3 seekg to end and then to begin
len:2
Hello, world
I think the the ouput should be nothing or Hello, world
for the fist case while the ouput is llo,world
.
std::basic_istream::seekg()
moves input position indicator to the given position.
According to the documentation the position is set by a numeric value.
The std::istreambuf_iterator
, when it is created for the given istream
, will point to the current input position.
So since seekg()
modifies the input position value for the given istream
, its call before creating iterator can have some affect on the iterator.
Now let's answer the question in the end of your post: why don't you observe empty string or full string in your code?
According to documentation seekg()
has two overloads:
std::ios_base::beg
, std::ios_base::end
, std::ios_base::curr
values.Now, in your code you pass only one argument to seekg()
method. Thus you invoke the first overload.
But you pass to it some std::istream::end
, which is, I assume, std::ios_base::end
value, somehow imported into std::istream
namespace. And you are lucky enough, so that its value is (or can be implicitly converted to) integer with value 2
.
So basically in your code you write in.seekg(2)
, which results in moving the input position of the stream to the third character in your string (the character with index 2
). As a result llo, world
is printed.
In order to move the input position to the end of the buffer use
in.seekg(0, std::ios_base::end);
In order to move the position to the beginning of the buffer use
in.seekg(0, std::ios_base::beg);
or in.seekg(0);
By the way, your third example, where you moved input position "to the end and back" worked because std::istream::beg
value is 0
. So effectively there you did call in.seekg(0)
before creating iterator and it read the string from its start.