问题
Sample code:
#include <iostream>
int main()
{
int x = 5;
std::cin >> x;
std::cout << x << '\n';
}
On one particular implementation the following behaviour occurs:
- Input:
6
; output6
- Input:
a
; output:0
- Input: (end-of-file); output
5
- Input: (whitespace followed by end-of-file); output
5
So, on failure, the cin >> x
is assigning 0
to x
if it was a failure to convert text to int; but it is not assigning 0
if the failure was due to end-of-file.
Is this correct behaviour? If not, what is the correct behaviour, according to the C++ Standard?
I have a recollection from previously discussing on SO that all cases should write 0
since C++11, but I could not find anything using the search feature; and the iostreams section of the C++ standard is pretty heavy going.
回答1:
According to 27.7.2.2.1 [istream.formatted.reqmts] paragraph 1 the first things for the formatted input function is to construct an std::istream::senty
object. Further processing depends on whether this object converts to true
or false
: nothing happens to the value if the sentry
converts to false
.
According to 27.7.2.1.3 [istream::sentry] paragraphs 5 and 7 the sentry
will convert to false
if the stream's flags are not std::ios_base::goodbit
. That is, if either a failure happend or EOF is reached the sentry
will convert to false
. As a result, the value
stays at 5
when EOF is reached after skipping whitespace, assuming std::ios_base::skipws
is set. Unsetting std::ios_base::skipws
should result in the value becoming 0
if there is, at least, one space.
Once parsing is actually done, the applies logic is defined in 22.4.2.1.2 [facet.num.get.virtuals] paragraph 3, Stage 3. The key section on the affected value is
...
The numeric value to be stored can be one of:
— zero, if the conversion function fails to convert the entire field.
ios_base::failbit
is assigned toerr
.— the most positive representable value, if the field represents a value too large positive to be represented in
val
.ios_base::failbit
is assigned toerr
.— the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented in
val
.ios_base::failbit
is assigned toerr
.— the converted value, otherwise.
The resultant numeric value is stored in
val
.
So, the observed behavior is correct.
With pre-C++11 the value was left unchanged in all cases. It was considered desirable to tell errors apart and indicate with the value which value should be represented. The discussions on how to change the behavior went on for a rather long time and were actually quite contentious.
That the value isn't changed if EOF is reached before attempting a conversion may be considered an error. I don't recall that case to be considered while the change was discussed.
回答2:
Yes, this is the correct behaviour since C++11.
- istream behavior change in C++ upon failure
The difference in what you're seeing is that a zero is written "when extraction fails", but extraction is not even attempted if EOF is already set on the stream… so nothing happens.
来源:https://stackoverflow.com/questions/32945923/value-stored-when-istream-read-fails