This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++11 status.
istream::operator>>(int&) brokenSection: 31.7.5.3.2[istream.formatted.arithmetic]Status:C++11Submitter: Martin SeborOpened: 2007-06-23Last modified: 2016-01-28
Priority:Not Prioritized
View all otherissues in [istream.formatted.arithmetic].
View all issues withC++11 status.
Discussion:
From message c++std-lib-17897:
The code shown in 31.7.5.3.2[istream.formatted.arithmetic] as the "as if"implementation of the two arithmetic extractors that don't have acorrespondingnum_get interface (i.e., theshort andint overloads) is subtly buggy inhow it deals withEOF, overflow, and other similarconditions (in addition to containing a few typos).
One problem is that ifnum_get::get() reaches the EOFafter reading in an otherwise valid value that exceeds the limits ofthe narrower type (but notLONG_MIN orLONG_MAX), it will seterr toeofbit. Because of the if condition testing for(err == 0), the extractor won't setfailbit (and presumably, return a bogus value to thecaller).
Another problem with the code is that it never actually sets theargument to the extracted value. It can't happen after the call tosetstate() since the function may throw, so we need toshow when and how it's done (we can't just punt as say: "it happensafterwards"). However, it turns out that showing how it's done isn'tquite so easy since the argument is normally left unchanged by thefacet on error except when the error is due to a misplaced thousandsseparator, which causesfailbit to be set but doesn'tprevent the facet from storing the value.
[Batavia (2009-05):]
We believe this part of the Standard has been recently adjustedand that this issue was addressed during that rewrite.
Move to NAD.
[2009-05-28 Howard adds:]
I've moved this issue from Tentatively NAD to Open.
The current wording ofN2857in 28.3.4.3.2.3[facet.num.get.virtuals] p3, stage 3 appears to indicate thatin parsing arithmetic types, the value is always set, but sometimes in additionto setting
failbit.
- If there is a range error, the value is set to min or max, else
- if there is a conversion error, the value is set to 0, else
- if there is a grouping error, the value is set to whatever it would be if grouping were ignored, else
- the value is set to its error-free result.
However there is a contradictory sentence in 28.3.4.3.2.3[facet.num.get.virtuals] p1.
31.7.5.3.2[istream.formatted.arithmetic] should mimic the behavior of 28.3.4.3.2.3[facet.num.get.virtuals](whatever we decide that behavior is) for
intandshort, and currently does not. I believe that thecorrect code fragment should look like:typedef num_get<charT,istreambuf_iterator<charT,traits> > numget;iostate err = ios_base::goodbit;long lval;use_facet<numget>(loc).get(*this, 0, *this, err, lval);if (lval < numeric_limits<int>::min()){ err |= ios_base::failbit; val = numeric_limits<int>::min();}else if (lval > numeric_limits<int>::max()){ err |= ios_base::failbit; val = numeric_limits<int>::max();}else val = static_cast<int>(lval);setstate(err);
[2009-07 Frankfurt]
Move to Ready.
Proposed resolution:
Change 28.3.4.3.2.3[facet.num.get.virtuals], p1:
-1-Effects: Reads characters from
in, interpreting themaccording tostr.flags(),use_facet<ctype<charT>>(loc), anduse_facet< numpunct<charT>>(loc), wherelocisstr.getloc().If an erroroccurs,valis unchanged; otherwise it is set to the resulting value.
Change 31.7.5.3.2[istream.formatted.arithmetic], p2 and p3:
operator>>(short& val);-2- The conversion occurs as if performed by the following code fragment (using the same notation as for the preceding code fragment):
typedef num_get<charT,istreambuf_iterator<charT,traits> > numget;iostate err = iostate_base::goodbit;long lval;use_facet<numget>(loc).get(*this, 0, *this, err, lval);if (err != 0) ;else if (lval < numeric_limits<short>::min() || numeric_limits<short>::max() < lval) err = ios_base::failbit;if (lval < numeric_limits<short>::min()){ err |= ios_base::failbit; val = numeric_limits<short>::min();}else if (lval > numeric_limits<short>::max()){ err |= ios_base::failbit; val = numeric_limits<short>::max();}else val = static_cast<short>(lval);setstate(err);operator>>(int& val);-3- The conversion occurs as if performed by the following code fragment (using the same notation as for the preceding code fragment):
typedef num_get<charT,istreambuf_iterator<charT,traits> > numget;iostate err = iostate_base::goodbit;long lval;use_facet<numget>(loc).get(*this, 0, *this, err, lval);if (err != 0) ;else if (lval < numeric_limits<int>::min() || numeric_limits<int>::max() < lval) err = ios_base::failbit;if (lval < numeric_limits<int>::min()){ err |= ios_base::failbit; val = numeric_limits<int>::min();}else if (lval > numeric_limits<int>::max()){ err |= ios_base::failbit; val = numeric_limits<int>::max();}else val = static_cast<int>(lval);setstate(err);