使用std :: istream :: peek()总是安全吗?

时间:2020-02-21 09:16:49

标签: c++ istream

我通常教我的学生处理文件输入的安全方法是:

while (true) {
    // Try to read
    if (/* failure check */) {
        break;
    }
    // Use what you read
}

这使我和许多人摆脱了传统,在大多数情况下都是错误的:

while (!is.eof()) {
    // Try to read
    // Use what you read
}

但是人们真的很喜欢这种形式的循环,所以在学生代码中看到这种循环已经很普遍了:

while (is.peek()!=EOF) { // <-- I know this is not C++ style, but this is how it is usually written
    // Try to read
    // Use what you read
}

现在的问题是:该代码是否有问题?在某些极端情况下,事情无法按预期进行吗?好的,这是两个问题。

编辑其他详细信息::在考试期间,您有时会向学生保证该文件将被正确格式化,因此他们不需要进行所有检查,只需要验证是否还有更多数据即可。在大多数情况下,我们处理二进制格式,这使您根本不必担心空格(因为数据有意义)。

虽然接受的答案是完全正确和正确的,但我仍然希望有人对peek()unget()的共同行为发表评论。

unget()之所以浮现在我的脑海,是因为我曾经观察到(我相信它是在Windows上)偷窥4096个内部缓冲区限制(如此有效地导致要加载新的缓冲区),而没有字节(上一个缓冲区的最后一个)失败。但是我可能是错的。因此,这是我的另一个疑问:我错过了一些已知的东西,可能在标准或某些库实现中编码正确。

1 个答案:

答案 0 :(得分:8)

is.peek()!=EOF告诉您输入流中是否还剩下字符,但不会告诉您下一次读取是否成功:

while (is.peek()!=EOF) {
    int a;
    is >> a;
    // Still need to test `is` to verify that the read succeeded
}

is >> a可能由于多种原因而失败,例如输入的内容实际上可能不是数字。

因此,如果您可以这样做,则没有任何意义

int a;
while (is >> a) { // reads until failure of any kind
    // use `a`
}

或者,也许更好:

for (int a; is >> a;) { // reads until failure of any kind
    // use `a`
}

或您的第一个示例,在这种情况下,循环中的is.peek()!=EOF将变得多余。

这是假设您希望循环在每次失败时都退出,遵循第一个代码示例,而不仅仅是在文件结尾。

相关问题