我刚刚在 这个 答案中发现了一条评论,说在循环条件中使用 iostream::eof
是“几乎肯定是错误的”。我通常使用 while(cin>>n)
类的东西——我猜它会隐式检查 EOF。
为什么使用 while (!cin.eof())
显式检查 eof 错误?
它与在 C 中使用 scanf("...",...)!=EOF
有什么不同(我经常使用没有问题)?
原文由 MAK 发布,翻译遵循 CC BY-SA 4.0 许可协议
我刚刚在 这个 答案中发现了一条评论,说在循环条件中使用 iostream::eof
是“几乎肯定是错误的”。我通常使用 while(cin>>n)
类的东西——我猜它会隐式检查 EOF。
为什么使用 while (!cin.eof())
显式检查 eof 错误?
它与在 C 中使用 scanf("...",...)!=EOF
有什么不同(我经常使用没有问题)?
原文由 MAK 发布,翻译遵循 CC BY-SA 4.0 许可协议
底线顶部: 通过正确处理空白,以下是如何使用 eof
(甚至比 fail()
更可靠用于错误检查):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
( 感谢 Tony D 提出的强调答案的建议。请参阅下面的评论,了解为什么这更强大的示例。 )
反对使用 eof()
的主要论点似乎缺少关于空白作用的重要微妙之处。我的主张是,明确地检查 eof()
不仅不是“ 总是错误 的”——这似乎是这个和类似的 SO 线程中最重要的观点——而且通过正确处理空白,它提供了更清洁和更可靠的错误处理,并且 始终是正确 的解决方案(尽管不一定是最简单的)。
总结建议的“正确”终止和阅读顺序如下:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
超出 eof 的读取尝试失败作为终止条件。这意味着没有简单的方法可以区分成功的流和由于 eof 以外的原因而真正失败的流。采取以下流:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
以一组 failbit
--- 结束 所有 三个输入。在第一个和第三个中,还设置了 eofbit
。因此,在循环之后,需要非常难看的额外逻辑来区分正确的输入(第一个)和不正确的输入(第二个和第三个)。
鉴于,采取以下措施:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
在这里, in.fail()
验证只要有东西要读,就是正确的。它的目的不仅仅是一个while循环终止符。
到目前为止一切都很好,但是如果流中有尾随空格会发生什么——这听起来像是对 eof()
作为终结者的主要担忧?
我们不需要放弃我们的错误处理;只是吃掉空白:
while( !in.eof() )
{
int data;
in >> data >> ws; // eat whitespace with std::ws
if ( in.fail() ) /* handle with break or throw */;
// now use data
}
std::ws
在设置 eofbit
而 failbit
--- 时跳过流中的任何潜在(零或更多)尾随空间。因此,只要至少有一个数据要读取, in.fail()
就可以按预期工作。如果全空流也可以接受,那么正确的形式是:
while( !(in>>ws).eof() )
{
int data;
in >> data;
if ( in.fail() ) /* handle with break or throw */;
/* this will never fire if the eof is reached cleanly */
// now use data
}
总结: 一个正确构造的 while(!eof)
不仅是可能的而且没有错,而且允许数据在范围内本地化,并且提供了一个更清晰的错误检查与正常业务的分离。话虽如此, while(!fail)
无疑是一个更常见和简洁的习语,并且在简单(每个读取类型的单个数据)场景中可能是首选。
原文由 sly 发布,翻译遵循 CC BY-SA 3.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
因为
iostream::eof
只会在读取流的末尾 后 返回true
。它 并不 表示下一次读取将是流的结尾。考虑一下(并假设下一次读取将在流的末尾):
反对这一点:
关于你的第二个问题:因为
是相同的
和 不 一样