C++ 为什么循环条件(即,`while(!stream.eof())`)中的iostream::eof被认为是错误的?
我刚刚在回答中发现一条评论说,在循环条件中使用C++ 为什么循环条件(即,`while(!stream.eof())`)中的iostream::eof被认为是错误的?,c++,iostream,c++-faq,C++,Iostream,C++ Faq,我刚刚在回答中发现一条评论说,在循环条件中使用iostream::eof“几乎肯定是错误的”。我通常使用while(cin>>n)-我猜这会隐式地检查EOF 为什么显式使用检查eof而(!cin.eof())错误 它与使用scanf(“…”,…)有何不同=EOF在C中(我经常使用它,没有问题)?因为iostream::EOF只会在读取流的结尾后返回true。它并不表示下一次读取将是流的结束 考虑这一点(并假设下一次读取将在流的末尾): 针对这一点: int data; while(inStrea
iostream::eof
“几乎肯定是错误的”。我通常使用while(cin>>n)
-我猜这会隐式地检查EOF
为什么显式使用检查eof而(!cin.eof())
错误
它与使用
scanf(“…”,…)有何不同=EOF
在C中(我经常使用它,没有问题)?因为iostream::EOF
只会在读取流的结尾后返回true
。它并不表示下一次读取将是流的结束
考虑这一点(并假设下一次读取将在流的末尾):
针对这一点:
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)
}
关于你的第二个问题:因为
if(scanf("...",...)!=EOF)
与
if(!(inStream >> data).eof())
if(!inStream.eof())
inFile >> data
与不相同
if(!(inStream >> data).eof())
if(!inStream.eof())
inFile >> data
因为
iostream::eof
仅在读取流的结尾后返回true
。它并不表示下一次读取将是流的结束
考虑这一点(并假设下一次读取将在流的末尾):
针对这一点:
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)
}
关于你的第二个问题:因为
if(scanf("...",...)!=EOF)
与
if(!(inStream >> data).eof())
if(!inStream.eof())
inFile >> data
与不相同
if(!(inStream >> data).eof())
if(!inStream.eof())
inFile >> data
因为如果程序员在(stream>>n)时不编写
,他们可能会这样写:
while(!stream.eof())
{
stream >> n;
//some work on n;
}
这里的问题是,如果不首先检查流读取是否成功,您就不能对n
执行某些工作,因为如果读取不成功,您的对n
执行的某些工作将产生不希望的结果
整个要点是,eofbit
、badbit
或failbit
在尝试从流中读取后设置为。因此,如果stream>>n
失败,那么eofbit
、badbit
或failbit
会立即设置,因此,如果您在编写时编写,它会更惯用(stream>>n)
,因为如果从流中读取失败,返回的对象stream
将转换为false
,因此循环停止。如果读取成功,循环继续,它将转换为true
。因为如果程序员在(stream>>n)期间不写入
,他们可能会这样写:
while(!stream.eof())
{
stream >> n;
//some work on n;
}
这里的问题是,如果不首先检查流读取是否成功,您就不能对n
执行某些工作,因为如果读取不成功,您的对n
执行的某些工作将产生不希望的结果
整个要点是,eofbit
、badbit
或failbit
在尝试从流中读取后设置为。因此,如果stream>>n
失败,那么eofbit
、badbit
或failbit
会立即设置,因此,如果您在编写时编写,它会更惯用(流>>n)
,因为如果从流中读取失败,则返回的对象流
将转换为假
,因此循环停止。如果读取成功且循环继续,则返回的对象将转换为真
。底线顶部:正确处理空白,下面的wing是如何使用eof
(甚至比fail()
更可靠地进行错误检查):
(感谢Tony D提出的强调答案的建议。请参见下面他的评论,以获取一个示例,说明为什么这样做更为有力。)
反对使用eof()
的主要论点似乎缺少了关于空格作用的一个重要细节。我的主张是,显式检查eof()
不仅不是“总是错误的”--在本线程和类似的SO线程中,这似乎是一个压倒一切的观点-,但通过正确处理空白,它提供了更干净、更可靠的错误处理,并且始终是正确的解决方案(尽管不一定是最简洁的)
以下是建议的“适当”终止和读取顺序的总结:
int data;
while(in >> data) { /* ... */ }
// which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
由于超出eof的读取尝试而导致的失败被视为终止条件。这意味着没有简单的方法来区分成功的流和由于eof以外的原因而真正失败的流。采用以下流:
12345
12345
a
while(在>>数据中)
终止时,所有三个输入都设置了一个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)
无疑是一个更为常见和简洁的习惯用法,在简单(每读取类型一个数据)的场景中可能更可取。