23

So I'm curious as to why this happens.

int main()
{
   bool answer = true;
   while(answer)
   {
      cout << "\nInput?\n";
      cin >> answer;
   }
return 0;
}

Expected behavior: 0 - Exits program, 1 - Prompts again, Any non-zero integer other than 1 - Prompts again

Actual behavior: 0 - As expected, 1 - As expected, Any non-zero integer other than 1 - Infinite loop

From http://www.learncpp.com/cpp-tutorial/26-boolean-values/

One additional note: when converting integers to booleans, 
the integer zero resolves to boolean false, 
whereas non-zero integers all resolve to true.

Why does the program go into an infinite loop?

  • 8
    +1 for a well-posed question. The boolean is a red herring; the real issue has to do with the way stream input works. Try the same thing with an int, and then enter a letter and see what happens ;-) – Cameron May 30 '12 at 23:44
  • Maybe I'm wrong but when you take input form command line...doesn't that become a string and so you're actually converting between string and boolean? Which might screw things up.... – Florin Stingaciu May 30 '12 at 23:46
  • Cameron makes a good point: a character can be converted to an integer. For example, `'A' == 65`, but the same thing happens. – chris May 30 '12 at 23:46
  • @Flo: No, that's not at all how command line input works. – Mooing Duck May 31 '12 at 00:17
  • @Flo: The conversion from string to boolean is _exactly_ the goal of `operator>>(istream&, bool&)`. Similarly, `operator>>(istream&, int&)` converts a string to integer. – MSalters May 31 '12 at 08:21

2 Answers2

24

In effect, the operator>> overload used for reading a bool only allows a value of 0 or 1 as valid input. The operator overload defers to the num_get class template, which reads the next number from the input stream and then behaves as follows (C++11 §22.4.2.1/6):

  • If the value to be stored is 0 then false is stored.

  • If the value is 1 then true is stored.

  • Otherwise true is stored and ios_base::failbit is assigned to err.

(err here is the error state of the stream from which you are reading; cin in this case. Note that there is additional language specifying the behavior when the boolalpha manipulator is used, which allows booleans to be inserted and extracted using their names, true and false; I have omitted these other details for brevity.)

When you input a value other than zero or one, the fail state gets set on the stream, which causes further extractions to fail. answer is set to true and remains true forever, causing the infinite loop.

You must test the state of the stream after every extraction, to see whether the extraction succeeded and whether the stream is still in a good state. For example, you might rewrite your loop as:

bool answer = true;
while (std::cin && answer)
{
    std::cout << "\nInput?\n";
    std::cin >> answer;
}
Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • +1: Much better answer than the accepted one because it explains that the standard mandates this behavior. – Jesse Good May 31 '12 at 00:08
  • Agreed :) Changed the answer to reflect giving a better understanding. Definitely an example of why input validation is always important :) –  May 31 '12 at 00:10
15

Because operator>> fails if the input is not 0 or 1, and when it fails, it does not consume input. So the loop consists of reading the digit and then un-reading it, repeatedly.

Try changing the code like this to see it:

if (cin >> answer) {
  cout << answer << endl;
} else {
  cerr << "oops" << endl;
  break;
}
James Youngman
  • 3,623
  • 2
  • 19
  • 21
  • 4
    Although you generally want to write `if (!(cin >> answer))` rather than `cin >> answer; if (cin.fail())` – Steve Jessop May 30 '12 at 23:49
  • Just tried this and the program sort of "hangs" if you just type in something and hit return. However, if you type it again, it goes on to evaluate the input. Why? –  May 30 '12 at 23:53
  • 3
    Downvoted for propagating the `if (cin.fail())` anti-pattern. Test the result of the operation (as @SteveJessop suggests) not the stream state. – Jonathan Wakely May 31 '12 at 01:37
  • 2
    @Jonathan: at least it's correct, you're complaining about style only. More often you see incorrect code that checks `bad()` or `eof()` instead of `fail()`. – Steve Jessop May 31 '12 at 08:25