Std::Cin Doesn't Throw an Exception on Bad Input

std::cin doesn't throw an exception on bad input

C++ iostreams don't use exceptions unless you tell them to, with cin.exceptions( /* conditions for exception */ ).

But your code flow is more natural without the exception. Just do if (!(cin >> input)), etc.

Also remember to clear the failure bit before trying again.

The whole thing can be:

int main()
{
int input;
do {
cout << "Please enter an integral value \n";
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
} while(!(cin >> input));
cout << input;
return 0;
}

While loop with try catch fails at bad cin input

You should think carefully what you want to do if user gives invalid input in this case. Usually in these cases the best solution is to read one line from the input and throw it away.

Try putting cin.clear() and std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n'); in your catch clause. cin.clear() clears the failure state in cin, and cin.ignore() throws away rest of the line waiting in the input buffer.

(And yes, you probably should rethink your use of exceptions).

How to handle wrong data type input

The reason the program goes into an infinite loop is because std::cin's bad input flag is set due to the input failing. The thing to do is to clear that flag and discard the bad input from the input buffer.

//executes loop if the input fails (e.g., no characters were read)
while (std::cout << "Enter a number" && !(std::cin >> num)) {
std::cin.clear(); //clear bad input flag
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //discard input
std::cout << "Invalid input; please re-enter.\n";
}

See the C++ FAQ for this, and other examples, including adding a minimum and/or maximum into the condition.

Another way would be to get the input as a string and convert it to an integer with std::stoi or some other method that allows checking the conversion.

standard input stream cin failing to prompt for input

12e is interpreted as the begin of a floating point number like 12e03. But the end is missing, so your stream is put on error (failbit). This state causes all subsequent input to fail until the failstate is cleared.

You could have an inner loop that checks such formatting errors:

while (...) {
...
while ( (cin >> x >> currency).fail() && !cin.eof()) { // loops as long as there's input and it's invalid
cout << "invalid format";
cin.clear();
}
if (cin.eof()) // if there's no longer input stop looping
break;
...
}

live demo

Note that you should initialize currency to something different than 'q' if you want to make sure that your loop is executed in every circumstance.

By the way, if you enter 12 e (with a space), 12 will be interpreted as the number and put to x and e to currency, as you expect.

Exception doesn't continue loop correctly

Bad input sets the failbit but doesn't throw exception by default.

you might use basic_ios::exceptions to have exception:

std::cin.exceptions(std::ifstream::failbit);
int numItems;

try
{
std::cout << "How many items to store?" << std::endl;
std::cin >> numItems;
if(numItems<0)
throw "Invalid Number.";
}
catch (const std::exception& e)
{
std::cin.clear();
std::string line;
std::getline(std::cin, line);
std::cerr << "'" << line << "' is not a number\n";
// ...
}
catch (const char* negativeValue)
{
std::cout << negativeValue << std::endl;
return 1;
}

C++ advice on exception handling

You say "10 positive inputs", but you have int number;. If your number is going to be an integer, then it can't take fractions like 33.44 for instance, and it also can't be NaN (so you wouldn't need to check for that). If you want to allow fractions, do double number instead. That aside, the check could look like this:

for (int i = 0; i < 10; i++) {
std::cin >> number;
if (std::cin.fail()) {
std::cin.clear();
std::string input;
std::cin >> input;
std::cout << "input failed! Invalid input: " << input << std::endl;
return -1;
}

After every inputted number, you do the std::cin.fail() check. If it failed, you can just return. In this example, I also made it print the invalid input. For that you need to call std::cin.clear(); to reset that error flag, and then you can put that invalid input into an std::string (which should work, unlike with the number). You need to include <string> for that. If you don't need to print anything, you can just return and forget about the clearing, the string and the output. Also, in this example, since the mess made by the invalid input is neatly cleaned up, you could take more (valid) inputs again if you don't return instead.

Next, checking for negative numbers:

if (number < 0) {
std::cout << "Error: Negative number!" << std::endl;
return -1;
}

Finally, the NaN check (for double):

if (isnan(number)) {
std::cout << "Error: number is NaN!" << std::endl;
return -1;
}

You need to include <math.h> for the isnan.

Putting it all together, it could look like this:

#include <iostream>
#include <string> // std::istream >> std::string
#include <math.h> // isnan

int main() {
double number;

for (int i = 0; i < 10; i++) {
std::cin >> number;
if (std::cin.fail()) {
std::cin.clear();
std::string input;
std::cin >> input;
std::cout << "input failed! Invalid input: " << input << std::endl;
return -1;
}
if (number < 0) {
std::cout << "Error: Negative number!" << std::endl;
return -1;
}
if (isnan(number)) {
std::cout << "Error: number is NaN!" << std::endl;
return -1;
}
}
return 0;
}

How to catch invalid input in c++?

You will need to #include <limits>

int x;
std::cout << "Enter a number: ";
std::cin >> x;
while(std::cin.fail()) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
std::cout << "Bad entry. Enter a NUMBER: ";
std::cin >> x;
}
std::cout << "x = " << x << std::endl;

There's a template for you.



Related Topics



Leave a reply



Submit