Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different EOF behavior with read versus ignore

Tags:

c++

iostream

I was recently just tripped up by a subtle distinction between the behavior of std::istream::read versus std::istream::ignore. Basically, read extracts N bytes from the input stream, and stores them in a buffer. The ignore function extracts N bytes from the input stream, but simply discards them rather than storing them in a buffer. So, my understanding was that read and ignore are basically the same in every way, except for the fact that read saves the extracted bytes whereas ignore just discards them.

But there is another subtle difference between read and ignore which managed to trip me up. If you read to the end of a stream, the EOF condition is not triggered. You have to read past the end of a stream in order for the EOF condition to be triggered. But with ignore it is different: you only need to read to the end of a stream.

Consider:

#include <sstream>
#include <iostream>
using namespace std;

int main()
{
    {
        std::stringstream ss;
        ss << "abcd";
        char buf[1024];
        ss.read(buf, 4);
        std::cout << "EOF: " << std::boolalpha << ss.eof() << std::endl;
    }

    {
        std::stringstream ss;
        ss << "abcd";
        ss.ignore(4);
        std::cout << "EOF: " << std::boolalpha << ss.eof() << std::endl;
    }
}

On GCC 4.4.5, this prints out:

EOF: false
EOF: true

So, why is the behavior different here? This subtle difference managed to confuse me enough to wonder why there is a difference. Is there some compelling reason that EOF is triggered "early" with a call to ignore?

like image 549
Channel72 Avatar asked Oct 10 '22 13:10

Channel72


2 Answers

eof() should only return true if you have already attempted to read past the end. In neither case should it be true. This may be a bug in your implementation.

like image 198
Puppy Avatar answered Oct 13 '22 06:10

Puppy


I'm going to go out on a limb here and answer my own question: it really looks like this is a bug in GCC.

The standard reads in 27.6.1.3 paragraph 23:

[istream::ignore] behaves as an unformatted input function (as described in 27.6.1.3, paragraph 1). After constructing a sentry object, extracts characters and discards them. Characters are extracted until any of the following occurs:

  • if n != numeric_limits::max() (18.2.1), n characters are extracted
  • end-of-file occurs on the input sequence (in which case the function calls setstate(eofbit), which may throw ios_base::failure(27.4.4.3));
  • c == delim for the next available input character c (in which case c is extracted). Note: The last condition will never occur if delim == traits::eof()

My (somewhat tentative) interpretation is that GCC is wrong here, because of the bold parts above. Ignore should behave as an unformatted input function, (like read()), which means that end-of-file should only occur on the input sequence if there is an attempt to extract additional bytes after the last byte in the stream has been extracted.

I'll submit a bug report if I find that enough people agree with this answer.

like image 20
Channel72 Avatar answered Oct 13 '22 04:10

Channel72