silhouette hustler
silhouette hustler

Reputation: 1763

Empty input variable that failed C++

I've found many posts saying I should be using the following code to empty the input variable in order to reset it:

    cin.ignore(numeric_limits<streamsize>::max(), '\n');

But what am I missing here since it's not compiling, it says expected an identifier when mouse hover over max();

code:

int Menu::getInput()
{
  int choice;

cin >> choice;

if (cin.fail())
{
    cin.clear();
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    return choice = 3;
}


return choice;

}

Upvotes: 1

Views: 74

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118445

The suggestions that you've read to use ignore() are just band-aids designed to workaround broken logic that attempts to read newline delimited text using operator>>.

The general situation goes something like this: "well, I should be reading lines of text that contain two integers, followed by a text string, ok, so I'll use operator>> to read two integers, then a std::string, from std::cin". And that's fine, as long as we all live in a perfect world. Unfortunately, we don't live in a perfect world, and when bad input is encountered, in the middle of this odyssey, we end up with:

  • A std::istream in an error/fail state.

  • An undeterminate amount of consumed input, with a partially read line.

Recovering from this mess is what the using ignore() is supposed to achieve, by reading and discarding the remainder of the partially-consumed line, until the next newline characters.

But wouldn't you agree that it's much better not end up in this ugly mess to start with, in the first place?

And that's why if you need to read something that's formatted as lines of text, you should simply use std::getline(), to read one line of text at time. What a novel idea!

And then, once you've read the next line of text into a simple, std::string buffer, if you feel like it you can go ahead and construct a std::istringstream object from it, and use operator>> to your heart's content.

And if parsing the line of text, using std::istringstream, fails for some reason, you only need to issue an appropriate complaint to the user, then simply loop back, and use std::getline() to read the next line of text from your input time, without having to screw around with resetting the stream's status, or discarding partially-processed line. That seems to me like a much simpler, easier approach, doesn't it?

It appears to me that most C++ courses, instructors, and textbooks, are doing a disservice to their students by unceremoniously sprinkling liberal usage of operator>>, without properly explaining that this is a completely wrong approach to reading input that's formatted as newline-delimited lines of text. This just leads to nothing but utter confusion, and buggy code.

Take this as an answer to your question: scrap completely what you're doing, and simply rewrite it, simply as:

int Menu::getInput()
{
   int choice;
   std::string buffer;

   if (!std::getline(std::cin, buffer).eof())
   {
       std::istringstream i(buffer);

       i >> choice;

       if (!i.fail())
            return choice;
   }

   return 3;
}

Money back guarantee: this approach guarantees to never mess up your std::cin's state, or leave it with partially-consumed input.

Upvotes: 3

Related Questions