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 和 not the 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(!stream.eof())
{
stream >> n;
//some work on n;
}
问题在于,如果没有先检查流读取是否成功,则无法执行 some work on n ,因为如果不成功,则 some work on n 将产生不需要的结果 .
整点是, eofbit , badbit 或 failbit 设置为 after an attempt is made to read from the stream. 所以如果 stream >> n 失败,那么 eofbit , badbit 或 failbit 会立即设置,所以如果你写 while (stream >> n) 会更加惯用,因为返回的对象 stream 转换为 false 如果有从流中读取有些失败,因此循环停止 . 如果读取成功并且循环继续,它将转换为 true .
while(!inStream.eof()){
int data;
// yay, not end of stream yet, now read ...
inStream >> data;
// oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit)
// do stuff with (now uninitialized) data
}
反对这个:
int data;
while(inStream >> data){
// when we land here, we can be sure that the read was successful.
// if it wasn't, the returned stream from operator>> would be converted to false
// and the loop wouldn't even be entered
// do stuff with correctly initialized data (hopefully)
}
4 回答
Bottom-line top: 通过正确处理空白区域,以下是如何使用
eof
(甚至,比fail()
更可靠用于错误检查):(感谢Tony D提出的强调答案的建议 . 请参阅下面的评论,了解为什么这样做更为强大 . )
反对使用
eof()
的主要论点似乎缺少关于白色空间作用的重要细微之处 . 我的主张是,明确地检查eof()
不仅不是“总是错误的” - 这似乎是在这个和类似的SO线程中的最重要的意见 - 但是通过适当处理白色空间,它提供了更清洁和更多可靠的错误处理,并且始终是正确的解决方案(尽管不一定是最简洁的) .总结一下建议的“正确”终止和读取顺序如下:
由超出eof的读取尝试引起的故障被视为终止条件 . 这意味着没有简单的方法可以区分成功的流和真正因eof之外的原因而失败的流 . 采取以下流程:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
对于所有三个输入,
while(in>>data)
以一组failbit
终止 . 在第一个和第三个中,eofbit
也被设置 . 因此,在循环之后,需要非常难看的额外逻辑来区分正确的输入(第一个)和不正确的输入(第二个和第三个) .鉴于,请采取以下措施:
在这里,
in.fail()
验证只要有东西要读,它就是正确的 . 它的目的不仅仅是一个while循环终结器 .到目前为止一切都那么好,但是如果流中有尾随空间会发生什么 - 听起来像
eof()
作为终结者的主要问题呢?我们不需要放弃我们的错误处理;只是吃掉了白色空间:
std::ws
在设置eofbit
和 not the failbit 时跳过流中任何可能的(零个或多个)尾随空格 . 因此,in.fail()
按预期工作,只要至少有一个数据可供读取 . 如果全空流也可以接受,那么正确的形式是:Summary: 正确构造的
while(!eof)
不仅可行且没有错误,而且允许数据在范围内进行本地化,并且可以像往常一样更清晰地将错误检查与业务分开 . 话虽如此,while(!fail)
无疑是一种更常见和简洁的习惯用语,并且在简单(每种读取类型的单一数据)场景中可能更受欢迎 .如果您使用3行中的第2行和2中的第3行,您将获得
ch
两次打印 . 所以cout在阅读之前 .因为如果程序员不写
while(stream >> n)
,他们可能写这个:问题在于,如果没有先检查流读取是否成功,则无法执行
some work on n
,因为如果不成功,则some work on n
将产生不需要的结果 .整点是,
eofbit
,badbit
或failbit
设置为 after an attempt is made to read from the stream. 所以如果stream >> n
失败,那么eofbit
,badbit
或failbit
会立即设置,所以如果你写while (stream >> n)
会更加惯用,因为返回的对象stream
转换为false
如果有从流中读取有些失败,因此循环停止 . 如果读取成功并且循环继续,它将转换为true
.因为
iostream::eof
只会在读取流结束后返回true
. 它并不表示下一次读取将是流的结束 .考虑一下(并假设接下来的读取将在流的末尾):
反对这个:
关于你的第二个问题:因为
是相同的
和 not 一样