Bottom-line top: With proper handling of white space, the following is how eof
can be used (and even, be more reliable than fail()
for error checking):
while( !(in>>std::ws).eof() ) {
int data;
in >> data;
if ( in.fail() ) /* Handle with 'break' or 'throw' */;
// Now use data
}
(Thanks Tony D for the suggestion to highlight the answer. See his comment below for an example to why this is more robust.)
The main argument against using eof()
seems to be missing an important subtlety about the role of white space. My proposition is that, checking eof()
explicitly is not only not "always wrong"—which seems to be an overriding opinion in this and similar Stack Overflow questions—, but with proper handling of white-space, it provides for a cleaner and more reliable error handling, and is the always correct solution (although, not necessarily the tersest).
To summarize what is being suggested as the "proper" termination and read order is the following:
int data;
while(in >> data) { /* ... */ }
// Which is equivalent to
while( !(in >> data).fail() ) { /* ... */ }
The failure due to read attempt beyond eof is taken as the termination condition. This means is that there is no easy way to distinguish between a successful stream and one that really fails for reasons other than eof. Take the following streams:
1 2 3 4 5<eof>
1 2 a 3 4 5<eof>
a<eof>
while(in>>data)
terminates with a set failbit
for all three input. In the first and third, eofbit
is also set. So past the loop one needs very ugly extra logic to distinguish a proper input (first) from improper ones (second and third).
Whereas, take the following:
while( !in.eof() )
{
int data;
in >> data;
if ( in.fail() ) /* Handle with break or throw */;
// Now use data
}
Here, in.fail()
verifies that as long as there is something to read, it is the correct one. It's purpose is not a mere while loop terminator.
So far so good, but what happens if there is trailing space in the stream—what sounds like the major concern against eof()
as terminator?
We don't need to surrender our error handling; just eat up the white-space:
while( !in.eof() )
{
int data;
in >> data >> ws; // Eat white space with 'std::ws'
if ( in.fail() ) /* Handle with 'break' or 'throw' */;
// Now use data
}
std::ws
skips any potential (zero or more) trailing space in the stream while setting the eofbit
, and not the failbit
. So, in.fail()
works as expected, as long as there is at least one data to read. If all-blank streams are also acceptable, then the correct form is:
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
}
Summary: A properly constructed while(!eof)
is not only possible and not wrong, but it allows data to be localized within scope and provides a cleaner separation of error checking from business as usual. That being said, while(!fail)
is inarguably a more common and terse idiom, and may be preferred in simple (single data per read type of) scenarios.
scanf(...) != EOF
won't work in C either, becausescanf
returns the number of fields successfully parsed and assigned. The correct condition isscanf(...) < n
wheren
is the number of fields in the format string. – RandolfEOF
if end of file is encountered before the first field conversion (successful or not). If end-of-file is reached between fields, it will return the number of fields succcessfully converted and stored. Which makes comparison toEOF
wrong. – Randolf.eof()
after the loop exits. – Randolfwhile(fail)
loop terminates with both an actual failure and an eof. Think about if you require 3 ints per iteration (say you are reading an x-y-z point or something), but there is, erroneously, only two ints in the stream. – Unrighteouswhile(!feof(file))
is always wrong?. Because the flag is set only after hitting the EOF. – Welleswhile (in >> x) { if (in >> y >> z) use(x, y, z); else FATAL("got an int not followed by 2 more!"); } if (!eof()) FATAL("didn't get integer where expected");
? If not, for what stream content would that not work nicely? – Harvest