This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of NAD status.
Section: 31.7.5.4 [istream.unformatted] Status: NAD Submitter: Howard Hinnant Opened: 2001-10-09 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [istream.unformatted].
View all issues with NAD status.
Discussion:
I think we have a defect.
According to lwg issue 60(i) which is now a dr, the description of seekg in 31.7.5.4 [istream.unformatted] paragraph 38 now looks like:
Behaves as an unformatted input function (as described in 27.6.1.3, paragraph 1), except that it does not count the number of characters extracted and does not affect the value returned by subsequent calls to gcount(). After constructing a sentry object, if fail() != true, executes rdbuf()->pubseekpos( pos).
And according to lwg issue 243(i) which is also now a dr, 27.6.1.3, paragraph 1 looks like:
Each unformatted input function begins execution by constructing an object of class sentry with the default argument noskipws (second) argument true. If the sentry object returns true, when converted to a value of type bool, the function endeavors to obtain the requested input. Otherwise, if the sentry constructor exits by throwing an exception or if the sentry object returns false, when converted to a value of type bool, the function returns without attempting to obtain any input. In either case the number of extracted characters is set to 0; unformatted input functions taking a character array of non-zero size as an argument shall also store a null character (using charT()) in the first location of the array. If an exception is thrown during input then ios::badbit is turned on in *this'ss error state. If (exception()&badbit)!= 0 then the exception is rethrown. It also counts the number of characters extracted. If no exception has been thrown it ends by storing the count in a member object and returning the value specified. In any event the sentry object is destroyed before leaving the unformatted input function.
And finally 27.6.1.1.2/5 says this about sentry:
If, after any preparation is completed, is.good() is true, ok_ != false otherwise, ok_ == false.
So although the seekg paragraph says that the operation proceeds if !fail(), the behavior of unformatted functions says the operation proceeds only if good(). The two statements are contradictory when only eofbit is set. I don't think the current text is clear which condition should be respected.
Further discussion from Redmond:
PJP: It doesn't seem quite right to say that seekg
is
"unformatted". That makes specific claims about sentry that
aren't quite appropriate for seeking, which has less fragile failure
modes than actual input. If we do really mean that it's unformatted
input, it should behave the same way as other unformatted input. On
the other hand, "principle of least surprise" is that seeking from EOF
ought to be OK.
Pre-Berlin: Paolo points out several problems with the proposed resolution in Ready state:
failbit
when it finds eofbit
already set, then
you can never seek away from the end of stream.[ 2009-07 Frankfurt ]
Moved to NAD. Will reopen if proposed resolution is supplied.
Proposed resolution:
Change 31.7.5.4 [istream.unformatted] to:
Behaves as an unformatted input function (as described in 27.6.1.3, paragraph 1), except that it does not count the number of characters extracted, does not affect the value returned by subsequent calls to gcount(), and does not examine the value returned by the sentry object. After constructing a sentry object, if
fail() != true
, executesrdbuf()->pubseekpos(pos)
. In case of success, the function calls clear(). In case of failure, the function callssetstate(failbit)
(which may throwios_base::failure
).
[Lillehammer: Matt provided wording.]
Rationale:
In C, fseek does clear EOF. This is probably what most users would
expect. We agree that having eofbit set should not deter a seek,
and that a successful seek should clear eofbit. Note
that fail()
is true only if failbit
or badbit
is set, so using !fail()
, rather
than good()
, satisfies this goal.