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

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

Priority: Not Prioritized

View all other issues in [istream.sentry].

View all issues with TC1 status.

Discussion:

Suppose that is.flags() & ios_base::skipws is nonzero. What should basic_istream<>::sentry's constructor do if it reaches eof while skipping whitespace? 27.6.1.1.2/5 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, 31.7.5.2 [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 27.6.1.1.2 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).