为什么在空流上调用时 std::istream::ignore 不返回?

Why does std::istream::ignore not return when called on an empty stream?

提问人:ulfben 提问时间:10/5/2017 更新时间:10/5/2017 访问量:693

问:

std::cin 是一个全局对象,因此我总是想在使用它之前将其设置为良好状态。但是,在未使用的 cin 上调用 ignore() 时,该函数不会返回。

请参阅下面的示例代码。如果没有用户干预,执行不会到达第 8 行 (cout)。在我的测试中,此行为与第二个参数(分隔符,我尝试过“\n”和 EOF)一致。

我已经浏览了几个在线参考资料,但我不明白为什么会发生这种情况。

#include <limits>
#include <iostream>
#include <string>
std::string readInput() {
    std::string input = "";
    std::cin.clear();
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cout << "We never get here..." << std::endl;
    std::getline(std::cin, input);
    return input;
}
int main() {    
    std::string foo = readInput();  
}
  1. 为什么在这种情况下 ignore() 不返回?
  2. 如何在使用安全地重置和清空 std::cin?
C++ C++11 标准 IOSTREAM

评论


答:

2赞 M.M 10/5/2017 #1

请参阅第二个参数。您请求读取不超过(包括“\n”)的字符并忽略它们。由于流上没有,这意味着在收到流之前进行阻止。'\n''\n'

希望很清楚,您应该仅在知道流上有时才进行此调用。'\n'

所以,第二个问题的答案是,在使用之前,什么都不做,因为无论如何流上都没有数据。

清除流的时间是在从中读取一些数据之后;然后,根据您使用的读取操作,您将知道是否存在换行符。

请注意,没有这样的操作“清除流上的任何内容”(这是有意设计)。相反,您的操作将是“清除行的其余部分”,其中“行”被定义为直到下一个换行符;输入将来自使用行的文件,或用户按 Enter 的交互式终端。

2赞 Jodocus 10/5/2017 #2

文档中所述:

ignore 的行为类似于 UnformattedInputFunction。构造并检查哨兵对象后,它会从流中提取字符并丢弃它们,直到出现以下任一情况:[...] 输入序列中的下一个可用字符 c 是 delim,由 Traits::eq_int_type(Traits::to_int_type(c), delim) 确定。提取并丢弃分隔符字符。如果 delim 为 Traits::eof()

因此,如果流为空,它将触发对相应流缓冲区的 underflow() 的调用,因为在您的例子中,ignore 正在等待 '\n'。

注意:当您想确保流缓冲区完全为空时,您可以调用 cin.rdbuf()->in_avail() 来获取仍在等待从输入缓冲区中提取的字符数,因此如果缓冲区为空,则为 0。然而,这高度依赖于实现,因为它可以与开箱即用的 Visual Studio 一起使用。另一方面,对于 GCC,您必须在之前调用 cin.sync_with_stdio(false) 才能打开内部缓冲。但是,它不会像这样与 LLVM 一起使用。