std::istream & operator >>(std::istream & ins, Rational & target)
{
int num, den;
char symb;
std::cout << "Please enter a rational number: ";
ins >> num >> symb >> den;
std::cout << std::endl;
if(validateInput(num, symb, den)){
target = Rational(num, den);
return ins;
}
else{
std::cin >> target;
}
}
bool validateInput(int num, char symb, int den)
{
if(symb != '/'){
std::cout << "Error: Illegal format. Please use '2/4'." << std::endl;
return false;
}
if((static_cast<int>(num) != num) && (static_cast<int>(den) != den)){
std::cout << "Error: Not a valid rational number." << std::endl;
return false;
}
if(den == 0){
std::cout << "Error: Cannot divide by 0." << std::endl;
return false;
}
return true;
}
It’s taking in a rational number in the format ‘x/y’, so 2/4 for instance.
It works fine if I type it right. If I type in 2p4, it will give the correct error (that I’m missing a ‘/’) and then ask for a new number. If 0 is in the denominator, it will also report the error and ask for a new number.
But checking to see if it’s a valid number doesn’t seem to work. If I type in ‘a/4’, it will just loop infinitely until it crashes. I can’t figure out why. Checking the debugger, it goes back to the ins >> statement, but doesn’t ask for anything from the user.
I’m assuming my logic is wrong somewhere. Note, I’m fairly new to C++, still learning. I was trying exception handling earlier, still haven’t learned it properly, so I settled back on something I’m more familiar with.
Thanks!
The basic gist of the issue is that C++ streams formatted extraction operators stop working if the state of the stream goes bad, and you have to reset the state for them to work again.
You have other issues, as well.
First of all, your validation function reveals your lack of experience:
static_cast<int>(intval) == intvalwill always be true and confirms nothing. Secondly, you fail to verify that you have indeed succeeded in extracting values from the stream (this is the cause for your infinite loop: all you do is fail the verification over and over again.)So, when you extract values, you should verify that all went alright, like this:
The “what should we do” part is far from obvious: you could just reset the stream and remove the first offending byte from it and try again, if you think that’s reasonable (and intuitive). However, the extraction may have also failed due to too large numbers, in which case this may lead odd behaviour: consider the following input (on an implementation with common
longsize):If you haven’t got any actual specifications, a thing to consider would be line-orientated input: first read a line and try to parse it; if it doesn’t look OK, ignore it and try the next one.