195. Should basic_istream::sentry's constructor ever set eofbit?

Section: [istream.sentry] Status: TC1 Submitter: Matt Austern Opened: 1999-10-13 Last modified: 2021-06-06 18:38:24 UTC

Priority: Not Prioritized

View all other issues in [istream.sentry].

View all issues with TC1 status.


Suppose that is.flags() & ios_base::skipws is nonzero. What should basic_istream<>::sentry's constructor do if it reaches eof while skipping whitespace? suggests it should set failbit. Should it set eofbit as well? The standard doesn't seem to answer that question.

On the one hand, nothing in [istream::sentry] says that basic_istream<>::sentry should ever set eofbit. On the other hand, [istream] paragraph 4 says that if extraction from a streambuf "returns traits::eof(), then the input function, except as explicitly noted otherwise, completes its actions and does setstate(eofbit)". So the question comes down to whether basic_istream<>::sentry's constructor is an input function.

Comments from Jerry Schwarz:

It was always my intention that eofbit should be set any time that a virtual returned something to indicate eof, no matter what reason iostream code had for calling the virtual.

The motivation for this is that I did not want to require streambufs to behave consistently if their virtuals are called after they have signaled eof.

The classic case is a streambuf reading from a UNIX file. EOF isn't really a state for UNIX file descriptors. The convention is that a read on UNIX returns 0 bytes to indicate "EOF", but the file descriptor isn't shut down in any way and future reads do not necessarily also return 0 bytes. In particular, you can read from tty's on UNIX even after they have signaled "EOF". (It isn't always understood that a ^D on UNIX is not an EOF indicator, but an EOL indicator. By typing a "line" consisting solely of ^D you cause a read to return 0 bytes, and by convention this is interpreted as end of file.)

Proposed resolution:

Add a sentence to the end of paragraph 2:

If is.rdbuf()->sbumpc() or is.rdbuf()->sgetc() returns traits::eof(), the function calls setstate(failbit | eofbit) (which may throw ios_base::failure).