While loop with try catch fails at bad cin input

20,490

Solution 1

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).

Solution 2

The most straight-forward (but not usually the easiest nor the fastest) way of dealing with validation of line-based input is to always read it line at a time. This way no extra whitespace (such as linefeed characters) is left unread in the buffer in any case, and discarding erroneous input is also quite automatic.

// Infinite loop for retrying until successful
while (true) {
    // Ask the user something
    std::cout << prompt;
    // Read the answer (one full line)
    std::string line;
    if (!std::getline(std::cin, line))
      throw std::runtime_error("End of input while expecting a value");
    // Put the line read into iss for further parsing
    std::istringstream iss(line);
    int val;
    // Read val from iss and verify that reading was successful and
    // that all input was consumed
    if (iss >> val && iss.get() == EOF) return val;
    std::cout << "Invalid input, try again!\n";
}

It is fun to make a BASIC style input function out of this:

template <typename Val> void input(std::string const& prompt, Val& val) {
    // (the above code goes here, slightly adjusted)
}

int main() {
    int w;
    double l;
    input("Enter weight in kg: ", w);
    input("Enter length in m: ", l);
    std::cout << "BMI: " << w / (l * l) << std::endl;
}

Notes for the pedantics who were going to downvote me:

  • function input should be specialized for std::string
  • exceptions thrown by the input function should be caught in main

Solution 3

My Problem was to block char input to a cin >> number

This error caused an 'infinite' loop showing my prompt cout << prompt with no way of exit but kill the process ...

The following shows what worked for me!

========================================

double fi_trap_d()    // function to return a valid range double catching errors  
{  
  double fi_game_sec;  
//-------------------------------------------  
   do  
   {  
    fi_game_sec = -1;  
    cout << fi_game_sec_c;  

        //------------------------------  
    cin.ignore();  // (1)
        //------------------------------  

    try  
    {  cin >> fi_game_sec;  cin.clear(); }  // (2)
        catch (...)  //out_of_range)  
      {  
        fi_game_sec = -1;  
        cout << " Dis am an error!\n";  
                     // just loop back as we asked for a number  
      }  
    } while (fi_game_sec < 1);  
//-------------------------------------------  
  return fi_game_sec;  
}  

========================================

Despite trying the " Dis am an error! " has NEVER shown up.

The key was (1) & (2) !

Share:
20,490
Admin
Author by

Admin

Updated on July 05, 2022

Comments

  • Admin
    Admin almost 2 years

    I can't seem to figure out why this falls into a loop after getting non-int input. I've tried cin.flush(), which doesn't seem to exist, cin.clear(), which seems like it should work, even cin.sync() after reading someone else post about it working, but didn't seem to make much sense. Also tried cin.bad().

    Thank you very much for any help

    Please enter the first number: f Sorry, I don't think that's a number?

    Please enter the first number: Sorry, I don't think that's a number?

    Please enter the first number: Sorry, I don't think that's a number?

    Please enter the first number: Sorry, I don't think that's a number?

    Please enter the first number: Sorry, I don't think that's a number?Sorry, you d on't get any more tries. Press any key to continue . . .

    #include <iostream>
    using namespace std;
    
    int main(){
        int entry;
        int attempts = 1;
        int result;
        while(attempts <= 5) {
            try {
                cout << "\n\nPlease enter the first number: ";
                cin >> entry;
                if (cin.fail())
                    throw "Sorry, I don't think that's a number?";
                if (entry < 0)
                    throw "Sorry, no negative numbers. Try something else? ";
                cout << "\nNow the second number: ";
                cin >> entry;
                cin.clear();
                cin.get();
            }
            catch (char* error) {
                cout << error;
                attempts++;
            }
        }
        if (attempts > 5)
            cout << "Sorry, you don\'t get any more tries.\n";
        system("pause");
        return 0;
    }