Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 585
Lightness Races in Orbit Avatar asked Oct 28 '16 15:10

Lightness Races in Orbit


1 Answers

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.

like image 167
Barry Avatar answered Oct 29 '22 01:10

Barry