!eof
From Cppwiki
- See also Marshall Cline's C++ FAQ Lite.
while (!stream.eof()) {
stream >> data;
process(data);
}
This assumes that stream >> data will stop at EOF after reading the final item in the stream. Two problems:
- It also stops at whitespace (including newline). If the final item is followed by whitespace, the loop will process it twice.
- It also stops on malformed input, and won't restart until you remove said input from the stream, in which case the stream will never reach EOF!
To fix, check for failure after reading each item!
while (true) {
stream >> data; // 1. Try to read data.
if (stream.fail()) break; // 2. If input failed, stop.
process(data); // 3. Process data, then go to step 1.
}
Note that (stream >> data) returns stream, allowing us to combine steps (1) and (2) into a single expression:
while (!(stream >> data).fail()) { // 1. Read data or stop.
process(data); // 2. Process data, then go to step 1.
}
Note also that (stream) evaluates to !(stream.fail()) when used in a boolean context, thereby allowing the following:
while (stream >> data) { // 1. Read data or stop.
process(data); // 2. Process data, then go to step 1.
}
The above loops will stop in case of malformed input. You might tell it to the next character in the stream and try to continue reading:
while (stream) {
if (stream >> data) {
process(data); // We read data; process it!
} else {
stream.clear(); // Something happened. Clear any errors
stream.ignore(1); // and try to ignore the next character.
}
}
What about EOF? In fact, there are three events to consider:
- stream.fail(): the stream failed to provide the requested data.
- stream.eof(): the stream ran out of data (EOF) during the last operation.
- stream.bad(): the stream lost integrity (i.e. something really "bad" happened) during the last operation. This typically indicates a problem with the stream's underlying buffer.
Note that these are independent events; you can succeed and reach EOF (or not), and you can fail and reach EOF (or not).
Also, there's another function, stream.good(), which is defined as !(stream.fail() || stream.eof() || stream.bad()) and means "nothing happened during the last input operation (or I already took care of it)."
These may be useful if you need to distinguish between the various cases. For example, you could write a slightly more verbose error recovery routine:
while (stream.good()) {
if (stream >> data) {
process(data); // We read data; process it!
} else if (stream.eof() || stream.bad()) {
break; // Can't really recover from these...
} else {
stream.clear(); // Something happened. Clear any errors
stream.ignore(1); // and try to ignore the next character.
}
}
Fun summary example:
std::istringstream stream("12 34 56x 789");
int data;
char c;
assert(stream.good() && !(stream.eof() || stream.bad() || stream.fail()));
stream >> data;
assert(data == 12);
assert(stream.good() && !(stream.eof() || stream.bad() || stream.fail()));
stream >> data;
assert(data == 34);
assert(stream.good() && !(stream.eof() || stream.bad() || stream.fail()));
stream >> data;
assert(data == 56);
assert(stream.good() && !(stream.eof() || stream.bad() || stream.fail()));
stream >> data;
assert(stream.fail());
assert(!(stream.good() || stream.eof() || stream.bad()));
stream.clear();
assert(stream.good() && !(stream.eof() || stream.bad() || stream.fail()));
stream >> c;
assert(c == 'x');
assert(stream.good() && !(stream.eof() || stream.bad() || stream.fail()));
stream >> data;
assert(data == 789);
assert(stream.eof());
assert(!(stream.good() || stream.bad() || stream.fail()));
stream >> data;
assert(stream.eof() && stream.fail());
assert(!(stream.good() || stream.bad()));

