Reputation: 3534
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
.
Upvotes: 1
Views: 113
Reputation: 123114
std::iostream::seekdir
which is actually std::ios_base::seekdir
is an implementation defined value of implementation defined type aliased as seekdir
.
It is meant to be passed as second parameter of the std::basic_istream<CharT,Traits>::seekg
overload that takes two parameters.
You have bad luck and seekdir
can be passed also to the overload that accepts 1 parameter. I did not find a gcc warning level that catches this.
As mentioned in comments, from the output we can infer that the value of std::istream::end
is 2
. The position of the stream is moved 2 steps forward. And what you probably wanted instead is
in.seekg(0, std::istream::end);
To move the cursor to the end of the input stream.
Upvotes: 4
Reputation: 206
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.
Upvotes: 3