Monday, 2 April 2018

c++ - Testing stream.good() or !stream.eof() reads last line twice










I have the following piece of code:




ifstream f("x.txt");
string line;
while (f.good()) {
getline(f, line);
// Use line here.
}


But this reads the last line twice. Why does this happen and how do I fix it?




Something very similar happens with:



ifstream f("x.txt");
string line;
while (!f.eof()) {
getline(f, line);
// Use line here.
}

Answer




You very, very rarely want to check bad, eof, and good. In particular for eof (as !stream.eof() is a common mistake), the stream currently being at EOF does not necessarily mean the last input operation failed; conversely, not being at EOF does not mean the last input was successful.



All of the stream state functions – fail, bad, eof, and good – tell you the current state of the stream rather than predicting the success of a future operation. Check the stream itself (which is equivalent to an inverted fail check) after the desired operation:



if (getline(stream, line)) {
use(line);
}
else {
handle_error();
}


if (stream >> foo >> bar) {
use(foo, bar);
}
else {
handle_error();
}

if (!(stream >> foo)) { // operator! is overloaded for streams
throw SomeException();

}
use(foo);


To read and process all lines:



for (std::string line; getline(stream, line);) {
process(line);
}



Pointedly, good() is misnamed and is not equivalent to testing the stream itself (which the above examples do).


No comments:

Post a Comment

casting - Why wasn't Tobey Maguire in The Amazing Spider-Man? - Movies & TV

In the Spider-Man franchise, Tobey Maguire is an outstanding performer as a Spider-Man and also reprised his role in the sequels Spider-Man...