Catch-ios::failure保持循环

Catch ios::failure keeps looping

本文关键字:循环 failure Catch-ios      更新时间:2023-10-16

下面的代码应该检查每个输入一次,并在输入不是数字时显示"不是数字"。

int input;
while (1 == 1){
    cout << "Enter a number: ";
    try{
        cin.exceptions(istream::failbit);
        cin >> input;
    }catch(ios::failure){
        cout << "Not a numbern";
        input = 0;
    }
}

问题是,当调用catch时(当它不是数字时),它会无休止地显示"无效数字",就像while()循环执行了几次但没有要求任何新输入一样。

while(true)while(1)[或for(;;)]是进行"永久循环"的常用方法。

您需要"清理"cin流中不可接受的输入。典型的方法是调用cin.ignore(1000, 'n');,它将忽略所有输入,直到下一个换行符[最多1000个字符-你可以选择一个更大的数字,但通常1000"足以到达换行符"。

几乎可以肯定的是(感谢Potatoswatter),您还需要在输入上调用cin.clear();,以删除failed状态,这样下一次输入才能成功。[cin.ignore()是进一步的输入,所以它需要在这之前进行——只是为了清楚]。

尽管未能将流中的字符提取到int中,但这些字符仍保留在流中,因此您可以尝试将它们提取为其他字符。

要完全跳过它们,请在catch块中运行std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');

然后,无论用户在下一个中输入什么,都将是流中的第一件事。也许这将是一个数字,所以您下一次尝试提取到int中会成功。

是的。您的try-catch语句在循环中。所以你尝试了一些东西,它失败了,抛出了一个异常,然后你抓住了这个异常,你永远不会退出或返回循环,所以你会再次做同样的事情。

但是,由于您的输入不是第一次处理的(而是抛出异常),因此不会在第二次、第三次或任何时候处理。

要继续,通过忽略输入直到下一个空格来处理异常:

int input;
while (1 == 1){
    cout << "Enter a number: ";
    try{
        cin.exceptions(istream::failbit);
        cin >> input;
    }catch(ios::failure){
        cout << "Not a numbern";
        input = 0;
        //the line below ignores all characters in cin until the space (' ')
        //(up to 256 characters are ignored, make this number as large as necessary
        cin.ignore(256, ' ');  
    }
}

顺便说一句,作为一条一般规则:异常应该是针对真正异常的东西,特别是因为处理异常会有开销。关于无效用户输入是否属于例外,存在争议。

作为一种替代方案,您可以制作一个更紧凑、同样正确的循环,没有以下异常:

int input;
while (true){  //outer while loop that repeats forever. Same as "while(1 == 1)"
    cout << "Enter a number: ";
    //The following loop just keeps repeating until a valid value is entered.
    //The condition (cin >> input) is false if e.g. the value is a character,
    //or it is too long to fit inside an int.
    while(!(cin >> input)) { 
      cout << "Not a number" << endl;
      input = 0;
    }
}