检查错误时,我的重载>>运算符中的无限循环

Rob*_*nto 1 c++ error-handling operator-overloading cin infinite-loop

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;
}
Run Code Online (Sandbox Code Playgroud)

它采用格式为'x/y'的有理数,例如2/4.如果我输入正确,它工作正常.如果我输入2p4,它将给出正确的错误(我错过了'/'),然后要求一个新号码.如果0在分母中,它也会报告错误并要求新号码.

但检查它是否是有效数字似乎不起作用.如果我输入'a/4',它将无限循环直到它崩溃.我无法弄清楚为什么.检查调试器,它会返回到ins >>语句,但不会向用户请求任何内容.

我假设我的逻辑在某处错了.注意,我是C++的新手,还在学习.我之前正在尝试异常处理,仍然没有正确学习它,所以我回过头来做一些我比较熟悉的事情.

谢谢!

eq-*_*eq- 5

该问题的基本要点是,如果流的状态变坏,C++流格式化的提取操作符将停止工作,并且您必须重置状态才能使它们再次工作.

您还有其他问题.

首先,您的验证功能揭示了您缺乏经验:static_cast<int>(intval) == intval永远是真实的并且没有任何确认.其次,您无法验证您是否确实成功从流中提取值(这是无限循环的原因:您所做的只是一遍又一遍地验证验证.)

因此,当您提取值时,您应该验证一切正常,如下所示:

int num, den;
char symb;
// Remember to flush unfinished lines
std::cout << "Please enter a rational number: " << std::flush; 
if (std::cin >> num >> symb >> den)
    // you extracted an integer, a character and an integer succesfully
    // perhaps check that the character is '/' and denominator is non-zero
else
    // there was an error: what should we do?
Run Code Online (Sandbox Code Playgroud)

"我们应该做什么"部分远非显而易见:您可以重置流并从中删除第一个有问题的字节,如果您认为合理(直观),请再试一次.但是,由于数字太大,提取可能也会失败,在这种情况下,这可能导致奇怪的行为:考虑以下输入(在具有通用long大小的实现上):

3111111111111111111111111111111111111111111111111/3
Run Code Online (Sandbox Code Playgroud)

如果您没有任何实际规格,需要考虑的是线路输入:首先读取一行并尝试解析它; 如果它看起来不正常,请忽略它并尝试下一个.