Why does std::ios_base::ignore() set the EOF bit?

c++, c++11, iostream, std

Solution

I think this is a libstdc++ bug (42875, h/t NathanOliver). The requirements on `ignore()` in [istream.unformatted] are:

Characters are extracted until any of the following occurs: — `n != numeric_limits<streamsize>::max()` (18.3.2) and `n` characters have been extracted so far — end-of-file occurs on the input sequence (in which case the function calls `setstate(eofbit)`, which may throw `ios_base::failure` (27.5.5.4)); — `traits::eq_int_type(traits::to_int_type(c), delim)` for the next available input character c (in which case c is extracted). Remarks: The last condition will never occur if `traits::eq_int_type(delim, traits::eof())`.

So we have two conditions (the last is ignored) - we either read `n` characters, or at some point we hit end-of-file in which case we set the `eofbit`. But, we are able to read `n` characters from the stream in this case (there are in fact 6 characters in your stream), so we will not hit end-of-file on the input sequence.

In libc++, `eof()` is not set and `tellg()` does return 6.

Problem

When I read all data from a stream, but make no attempt to read past its end, the stream's EOF is not set. That's how C++ streams work, right? It's the reason this works: ``` #include <sstream> #include <cassert> char buf[255]; int main() { std::stringstream ss("abcdef"); ss.read(buf, 6); assert(!ss.eof()); assert(ss.tellg() == 6); } ``` However, if instead of `read()`ing data I `ignore()` it, EOF is set: ``` #include <sstream> #include <cassert> int main() { std::stringstream ss("abcdef"); ss.ignore(6); assert(!ss.eof()); // <-- FAILS assert(ss.tellg() == 6); // <-- FAILS } ``` This is on GCC 4.8 and GCC trunk (Coliru). It also has the unfortunate side-effect of making `tellg()` return `-1` (because that's what `tellg()` does), which is annoying for what I'm doing. Is this standard-mandated? If so, which passage and why? Why would `ignore()` attempt to read more than I told it to? I can't find any reason for this behaviour on cppreference's `ignore()` page. I can probably `.seekg(6, std::ios::cur)` instead, right? But I'd still like to know what's going on.

Original source