• 13
• 18
• 19
• 27
• 10

Error handling with cin [solved]

This topic is 3901 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

The following code breaks if I type anything other than a number:
map options = ...;

int choice;
while(true) {
cout << "Input selection:\n> ";
cin >> choice;
if(options.count(choice) > 0)
return choice;
cout << "Invalid selection.\n";
}


----------Output---------- Input selection: > 489 Invalid selection. Input selection: > No. Invalid selection. Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection Input selection: > Invalid selection (repeats until program is terminated) How do I make my program reject non-digits instead of breaking like this? [Edited by - Dathgale on July 13, 2007 8:59:06 PM]

Share on other sites
Set choice to 0 after each loop.
while(true) {	cout << "Input selection:\n> ";	cin >> choice;	if(options.count(choice) > 0)		return choice;	cout << "Invalid selection.\n";        choice = 0;}

Share on other sites
You have to set it up as a string stream... then parse based on that.
-durfy

Share on other sites
Stormtrooper, thanks, but that does not do anything because the line 'cin >> choice;' overwrites the 0. I just tried it to make sure.

EDIT:
Durfy, can you reword that as a series of steps so a noob can understand? I have little experience with C++.

Share on other sites
1) #include<sstream.h>
or #include<sstream>
using namespace std;

2) sstream ss;
cout<<"Enter a number:";
cin>>ss;
if (ss (wierd parsing stuff here)) {
cout<<"Thats not a number dummy!";
}
else {
cout<<"Thank you for following instructions!";
}

3) Go to msdn.com and search string stream and there is much more info there as i haven't used it in a while and am not totally sure I used it right;
-durfy

Share on other sites
You can check a stream for a parsing problem on extraction by testing the stream object as a boolean value. Ex:
  int i;  std::cin >> i;  if (!std::cin) {    // not an int, do stuff  } else {    // an int do other stuff  }

Share on other sites
In addition to what SiCrane said, operator>> for std::cin actually returns an istream object, which enables you to do the following:

#include <limits>while (std::cout << "Input selection:\n> " && (!(std::cin >> choice) || options.count(choice) <= 0)){	std::cin.clear();	std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');	std::cout << "Invalid selection.\n";}return choice;

Note that you need to clear the bad state of the stream in the case of bad input, or else it won't allow further input and the loop will become endless. For further information, see this website.

Hope this helps.

Share on other sites
That worked. Using cin.clear() by itself had no apparent effect, but I didn't realize that I had to ignore the extra characters left over after attempting to parse a number. Thanks a lot.

Share on other sites
Quote:
 Original post by StormtrooperSet choice to 0 after each loop.while(true) { cout << "Input selection:\n> "; cin >> choice; if(options.count(choice) > 0) return choice; cout << "Invalid selection.\n"; choice = 0;}

Wrong. The problem is with the state of std::cin, not the contents of choice.

Quote:
 Original post by DurfyYou have to set it up as a string stream... then parse based on that.-durfy

Wrong; although this approach generally makes things easier, it's not mandatory; and besides, actually remembering how to set it up would be more useful.

Quote:
 Original post by DathgaleStormtrooper, thanks, but that does not do anything because the line 'cin >> choice;' overwrites the 0. I just tried it to make sure.

Wrong about why it's wrong. Reading from cin is skipped as long as the stream is in the invalid state, so it will just use the existing 0 value immediately - if there's no 0 in your map, it won't get returned. (Also, using .count() on something you know to be a map is a little strange, although valid; the usual way to look things up is with .find() or the operator[]. The .count() function is really only provided for std::map for people who want to write template code that works with both ordinary maps and multimaps.)

Quote:
 Original post by SiCraneYou can check a stream for a parsing problem on extraction by testing the stream object as a boolean value. Ex: int i; std::cin >> i; if (!std::cin) { // not an int, do stuff } else { // an int do other stuff }

Right, but not enough information to be useful.

Quote:
 Original post by DarklighterIn addition to what SiCrane said, operator>> for std::cin actually returns an istream object, which enables you to do the following:*** Source Snippet Removed ***Note that you need to clear the bad state of the stream in the case of bad input, or else it won't allow further input and the loop will become endless. For further information, see this website.Hope this helps.

Right, and finishes off being useful WRT that approach.

For the stringstream approach:

#include <sstream> // in addition to whatever else you hadwhile (true) {	std::cout << "Input selection:\n> ";	std::string input;	std::getline(std::cin, input);	// "If we can read from an input-stringstream constructed from input, into choice, and"	int choice; // declare variables near first use, please.	if ((std::istringstream(input) >> choice) && 	// "the result of looking for choice is not the end iterator (which is returned to indicate not-found)"	    (options.find(choice) != options.end())) {		return choice;	}	std::cout << "Invalid selection.\n";}