【问题标题】:Is it always safe to use std::istream::peek()?使用 std::istream::peek() 总是安全的吗?
【发布时间】:2020-02-21 09:16:49
【问题描述】:

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

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

【问题讨论】:

  • 你会想看看Why !.eof() inside a loop condition is always wrong. 第四个条件稍微好一点。通常总是更好地使用读取功能本身来控制读取,例如while (std::cin &gt;&gt; var) { /* handle var */ }while (getline (fp, str)) { /* handle string */ } 等等...

标签: c++ istream


【解决方案1】:

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

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

is &gt;&gt; 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 将变得多余。

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

【讨论】:

  • for(int a; is &gt;&gt; a;)
  • 好的,这一切都清楚了。所以,如果我假设读取失败的唯一原因是到达文件末尾(一个非常强大和慷慨的假设),那么这个想法是正确的,对吧?即使以后有人玩std::istream::unget(),这也应该有效?
  • @CostantinoGrana 你确定这是一个好的假设吗?例如,如果输入末尾有空格,则peek() 不会返回 EOF,尽管所有格式化读取都会失败。我不确定您对unget() 有什么想法,但我想unget() 可以将peek() 返回EOF 更改为不返回EOF。
  • @walnut 不,我敢肯定这不是一个好的假设。但是在考试期间,您有时会向学生保证文件格式正确,因此他们不需要进行所有检查。大多数时候我们处理二进制格式,这让你完全不用担心空格(因为数据都是有意义的)。我想到了unget() 的东西,因为我曾经观察到(我相信它是在 Windows 上)通过查看 4096 缓冲区限制,取消获取前一个字节(前一个缓冲区的最后一个)失败。但我可能是错的。所以这是我的疑问:我错过了一些已知的东西。
  • @CostantinoGrana 您可能想在您的问题中澄清这些问题,以便其他人可以添加答案。老实说,我认为我对流库的内部了解不够充分,无法回答这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-17
  • 2018-03-31
  • 2020-05-08
  • 1970-01-01
  • 2011-10-15
  • 1970-01-01
相关资源
最近更新 更多