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

Is it always safe to use std::istream::peek()?

本文关键字:安全 std istream peek 使用      更新时间:2023-10-16

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

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内部缓冲区限制(如此有效地导致加载新的缓冲区(,取消设置前一个字节(前一个缓冲区的最后一个(失败了。但我可能错了。所以这是我额外的怀疑:我错过了一些已知的东西,这些东西可能在标准或一些库实现中编码得很好。

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将变得多余。

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