26

Take from: cppreference

Until C++11:

If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.

Since 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<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set.

Due to this change, this means that the following snippet:

int x = 1;
std::cin >> x;
return x;

in the event that the numerical conversion fails, will return 1 before C++11, and 0 otherwise.

Why would the standard committee introduce such a subtle breaking change? Or rather, what kind of code was possible prior to C++11 that warranted this change?

Borgleader
  • 15,826
  • 5
  • 46
  • 62
  • I would expect undefined value if the operation fails, so I don't think that the *actual* quantity of code that change breaks is that big. – Bartek Banachewicz Oct 22 '13 at 15:48
  • @Bartek: What _you_ expect and what actually happen in either case do not match. :) – Lightness Races in Orbit Oct 22 '13 at 15:49
  • 1
    It's your responsibility to check for errors. That's both `pre-C++11` and `C++11` and will be in future versions too (most likely). It's simply your fault for not checking but relying on some implementation detail. – stefan Oct 22 '13 at 15:50
  • @stefan Yes, I agree. But it remains a breaking change and I'm wondering why it was made. Error detection considerations aside there must have been a reason that prompted it. The code was simply to show the resulting change in behavior. – Borgleader Oct 22 '13 at 15:57
  • 2
    @stefan That's ridiculous. Expecting the value unmodified relies on implementation details but checking the failbit doesn't? WTF? Why do we even have interface specifications and documentation? Can you explain why it is that in "If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set." the "value is left unmodified" part is an implementation detail, but the "failbit is set" part isn't? You can't selectively cherry-pick documented behaviour and call it an implementation detail. – R. Martinho Fernandes Oct 22 '13 at 15:57
  • @R.MartinhoFernandes Simple, it's consistent among the methods of streams to set the fail bit on error. Yes, it technically is also implementation detail, but a much bigger thing. – stefan Oct 22 '13 at 16:00
  • @Borgleader Unless a member of the comittee comes here, it's not very likely to get a good answer. Why don't you ask that in their google group? – stefan Oct 22 '13 at 16:01
  • 4
    @stefan No. It is most definitely not an implementation detail. It's the *specified behaviour* of `operator>>`. It is written right there in the specification. What other parts of the specified behaviour of `operator>>` do you selectively ignore? – R. Martinho Fernandes Oct 22 '13 at 16:02
  • @R.MartinhoFernandes Detecting an error of `std::cin >> x` is impossible without checking the failbit. The equality of values (pre11) and the special value 0 (or whatever) (11) is only an _indicator_ that something might be wrong, but not a check. The point is: if you want to know if it's errornous, check the bit. – stefan Oct 22 '13 at 16:04
  • 2
    @stefan My point is: if you want it to return 1 on error, the code is perfectly fine. Well, was. It's not the fault of the person that wrote the code that the specification changed in an incompatible way. – R. Martinho Fernandes Oct 22 '13 at 16:05
  • @stefan: No, the point is, the _other_ behaviour of a failing extraction has changed in a breaking way. – Lightness Races in Orbit Oct 22 '13 at 16:06
  • @R.MartinhoFernandes Ahem, yes it is (and I just wrote so, don't you read?): If you want to return `1` _on error_ you have to check the failbit. If you want to return `1` on "possible error", yes, the specification indeed changed in an incompatible way. But I don't see a reasonable application of "let me have a possible error". – stefan Oct 22 '13 at 16:09
  • It's not about the 1. It's about not losing the previous value. – R. Martinho Fernandes Oct 22 '13 at 16:11
  • Well, since I see a lot of reasonable applications for "read a value if possible, or keep the old one if not" I'll file "that's stupid" as your opinion and leave it at that. – R. Martinho Fernandes Oct 22 '13 at 16:17
  • 4
    **See also [this answer](http://stackoverflow.com/a/19523324/560648).** Seemingly, it's not as if we could ever truly rely on this behaviour anyway, so in practice it's no great loss. – Lightness Races in Orbit Oct 22 '13 at 16:25

2 Answers2

7

It seems as originally specified, the operator>>s were broken in some cases (i.e. strictly speaking couldn't exist). This is the "fix".

In a draft from early 2011, The Standard is basically the same in this regard as it was in 2003. However, in a library defect report opened by Matt Austern (in 1998!), num_get<>::get() doesn't exist for short and int. So they were changed to use the long version, and check the read number falls within the correct range.

The defect report is here.

(Doesn't really explain why they didn't think they could keep the originally intended behaviour, but it is why this part of The Standard was changed.)

BoBTFish
  • 19,167
  • 3
  • 49
  • 76
2

It's more the C++ way of doing things to store zero in the non-const reference input x then returning the original value in case of error.

In order to keep the original value in case of an error condition the library would have to work with a temporary. It can't simply use the space provided by x without storing the original value somewhere. Then it might also have to do a copy to x at some point once the error conditions are known. How else would you get the original value if there's an error or the read input otherwise. So everyone pays the price regardless of whether they want this behavior or not.

So returning the original value in case of error isn't C++ at all. If you want that behavior simply pay for it yourself - create a temporary and pass its non-const reference to operator>>, something like:

int x = 1;
int temp;
if (std::cin >> temp) 
    x = temp;
return x;
Paul Evans
  • 27,315
  • 3
  • 37
  • 54