使用 std::istream::peek() 总是安全的吗?
Is it always safe to use std::istream::peek()?
我通常教我的学生处理文件输入的安全方法是:
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
将变得多余。
这是假设您希望循环在每次失败时退出,遵循您的第一个代码示例,而不仅仅是在文件结束时。
我通常教我的学生处理文件输入的安全方法是:
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
将变得多余。
这是假设您希望循环在每次失败时退出,遵循您的第一个代码示例,而不仅仅是在文件结束时。