When you insert a letter this happens:
operator>>
extracts characters from the stream and try to convert them to a number;
- it fails in the conversion, so it sets the stream state to
ios::failbit
and returns; opt
probably is untouched (the standard delegates this stuff to the locale library, which is a zone of C++ that I never really understood - for the brave enough, it's at §22.2.2.1.2);
- since it returned and (probably)
opt
is left as it is, the loop continues;
- when the execution returns to
std::cin >> opt;
, operator>>
sees that the state is still ios::failbit
, so it doesn't even try to extract anything;
- goto 3.
To fix the problem, you should clean the error state and remove the "wrong" characters from the input buffer. Since you probably don't want to add all that code to every cin>>
, it's useful to create a function to deal with this common problem; personally, I created this little header (AcquireInput.hpp
) that has proven useful many times:
#ifndef ACQUIREINPUT_HPP_INCLUDED
#define ACQUIREINPUT_HPP_INCLUDED
#include <iosfwd>
#include <limits>
#include <string>
template<typename InType> void AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString, InType & Result)
{
do
{
Os<<Prompt.c_str();
if(Is.fail())
{
Is.clear();
Is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Is>>Result;
if(Is.fail())
Os<<FailString.c_str();
} while(Is.fail());
}
template<typename InType> InType AcquireInput(std::ostream & Os, std::istream & Is, const std::string & Prompt, const std::string & FailString)
{
InType temp;
AcquireInput(Os,Is,Prompt,FailString,temp);
return temp;
}
/* Usage example:
//1st overload
int AnInteger;
AcquireInput(cout,cin,"Please insert an integer: ","Invalid value.\n",AnInteger);
//2nd overload (more convenient, in this case)
int AnInteger=AcquireInput(cout,cin, "Please insert an integer: ","Invalid value.\n");
*/
#endif