使用cin.fail()时存在Ininite循环

Inifinite loop when using cin.fail()

本文关键字:存在 Ininite 循环 cin fail 使用      更新时间:2023-10-16

每当我输入无法转换为整数的内容时,我都会得到一个无限循环。有什么建议吗?

cout << "Selection: ";
cin >> choice;
while((choice < 0)||(choice > 6)||(cin.fail())) {
    cout << "That isn't a number." << endl;
    cin.clear();
    cout << "Selection: ";
    cin >> choice;
}

仅仅读取clear是不够的:cin将一次又一次地读取该字符。你需要ignore它。

std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n')是实现这一点的常用方法。


另一种方法是将整行读取为字符串,然后对其进行解析(如C#/Java ecc.)

string s;
getline(cin, s);
int n = std::stoi(s);

请注意,std::stoi可以抛出std::invalid_argumentstd::out_of_range。使用此方法,您不必忽略任何内容(因此更容易处理/学习),尽管您可能需要捕捉可能的异常。

请注意,即使被其他语言使用,这种方法在逻辑上也是不正确的:只有在异常情况下(例如内部I/O故障),才应抛出异常。相反,错误的用户输入是您所期望的。

这在isocpp.org常见问题中有介绍。它建议使用while (std::cin >> i)形式的循环,以便在提取失败时终止循环。提取将继续失败,因为std::cin不会从输入流中提取无效字符。要放弃这些,您需要使用std::cin.ignore。通常,您可以将任意大的数字作为第一个参数,但习惯使用std::numeric_limits<std::streamsize>::max()#include <limits>)。

循环可以简洁地写为:

while(!(std::cin >> choice) || (choice < 0) || (choice > 6)) {
    cout << "Invalid choice." << endl;
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
}

或者,您可以将提示置于循环条件中:

while((std::cout << "Selection: ")
        && (!(std::cin >> choice) || (choice < 0) || (choice > 6))) {
    cout << "Invalid choice." << endl;
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
}

不需要"无效字符"诊断,因为它包含在!(std::cin >> choice)中。示例运行:

Selection: a
Invalid choice.
Selection: b
Invalid choice.
Selection: c
Invalid choice.
Selection: d
Invalid choice.
Selection: 15
Invalid choice.
Selection: 10
Invalid choice.
Selection: 5