Why does stringstream >> change value of target on failure?
From this reference:
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set (until C++11)
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits::max() or std::numeric_limits::min() is written and failbit flag is set. (since C++11)
It seems that your compiler is compiling in C++11 mode, which changes the behavior.
The input operator uses the locale facet std::num_get
whose get
function invokes do_get
. For C++11 it's specified to use std::strtoll
et. al. type of functions. Before C++11 it apparently used std::scanf
style parsing (going by the reference, I don't have access to the C++03 specification) to extract the numbers. The change in behavior is due to this change in parsing the input.
The operator >> is a formatted input operator.
As such is dependent on the locale for how input is read from the stream:
[istream.formatted.arithmetic]
As in the case of the inserters, these extractors depend on the locale’s num_get<> (22.4.2.1) object to perform parsing the input stream data. These extractors behave as formatted input functions (as described in 27.7.2.2.1). After a sentry object is constructed, the conversion occurs as if performed by the following code fragment:
typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);
As we can see above the value is actually set by the numget
facet of the locale imbuded onto the stream.
num_get virtual functions [facet.num.get.virtuals]
Stage 3:
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 to err.
- the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
- the most negative representable value or zero for an unsigned integer type, if the field repre- sents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
The definition of stage 3 changed drastically between n2723 -> n2798
Where do I find the current C or C++ standard documents?
num_get virtual functions [facet.num.get.virtuals]
Stage 3: The result of stage 2 processing can be one of:
- A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val . This value is stored in val and ios_base::goodbit is stored in err .
- The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err.