0

I am looking through the istream class and I don't see a method that cleans completely the buffer and sets the input to be ready for a next "clean" input.

I defined the extraction operator for my class, and in my main program I ask the user for an input, like this:

while (true) {
    try {
        cout << "Enter input: ";
        MyClass c;
        cin >> c;
        return c;
    } catch(const MyException& e) {
        cerr << "Error\n";
    }
}

If I enter an unexpected incorrect input I am trapped in an infinite loop.

In my overriden extractin method I control when the input is not correct and the exception is thrown, all this is ok. I just want to also clean the istream object so I prevent the infinite loop.

dabadaba
  • 9,064
  • 21
  • 85
  • 155

1 Answers1

1

Firstly, the inserters/extrators for your classes shouldn't throw exceptions. IOStreams were designed not to throw exceptions by default and to remain consistent I would recommend that you not throw custom exceptions from your I/O operators.

As Dieter said, you're better off setting the std::ios_base::failbit flag in the stream state instead of throwing. You can do this using the setstate() method. Once you do that, you can check for a valid extraction with an if() statement. To answer your question, once you determine if the input is invalid, you clear the stream state, and clear the buffer for new input by calling ignore() discard the rest of the characters:

while (std::cout << "Enter input: ")
{  
    X x;
    if (!(std::cin >> x))
    {
        std::cout << "Invalid. Try again.\n";
        std::cin.clear();
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        continue; // or break if needed
    }
    // handle good input and break if needed
}
David G
  • 94,763
  • 41
  • 167
  • 253
  • These methods dont throw exceptions, the constructor does, it is called in the extraction method. The clear and ignore methods worked for me, that's the answer I was looking for, however I am calling them inside the extraction method, not outside of it. The responsible of cleaning the buffer should be the programmer's, not the user's. – dabadaba Apr 13 '14 at 12:19
  • @dabadaba If the constructor throws an exception within the extractor, then it is as if the extractor itself is throwing an exception. You should still wrap the constructor within a `try catch` block and set `failbit` in the stream as I've said. Also, I don't 100% agree that cleanup should be the programmers job. For example, the standard streams do not clean up invalid input. Moreover, if you're going to `clear()` the stream state when invalid input is present, how will the user ever know if he entered in invalid input in the first place? – David G Apr 13 '14 at 12:25
  • @dabadaba I suppose you can cache the stream state, do the cleanup, and then reset the stream state in the stream. That would be good however. – David G Apr 13 '14 at 12:46
  • he will know that he entered an invalid input because an exception is thrown, even though you say that these methods should not throw any exceptions – dabadaba Apr 13 '14 at 18:04