Reputation: 61
I've read that the following is an anti-pattern:
while(in.good()) {
// ...
}
But this is preferred:
while(operation) {
}
However, the stream has a conversion operator to bool that returns !fail()
. Isn't !fail()
the same as good()
? If not, why aren't these two functions symmetrical? I'd expect it to be similar to true == !false
.
Upvotes: 6
Views: 413
Reputation: 2627
in.good() is equal to: [ios documentation]
! ( in.eof() || in.fail() || in.bad() )
Upvotes: 0
Reputation: 241671
in.good()
is true if the previous read operation succeeded without EOF being encountered. (It is possible for EOF to be encountered even if a read operation succeeds.) So if in.good()
is false, either the previous read operation failed -- in which case, the next one will also fail -- or EOF was encountered -- in which case the next read operation will also fail. So if in.good()
is false, the next read operation will definitely fail. If we want to know whether it is worth trying to do a read operation, we should test in.good()
.
But the fact that in.good()
is true does not guarantee anything. Suppose that in
ends with whitespace, which is normally the case since text files are required to end with a newline. Formatted read operations stop at the first whitespace character, and unget
it back into the input stream, so if the previous read operation read the last data item, it still did not leave the stream at EOF, and in
will still be good
. [See note 1]. So if your loop looks like this:
while (in.good()) {
in >> x;
/* Do something with x assuming that it is valid */
}
then you won't notice when the last in >> x
failed, and you'll end up using an undefined value of x
in the last loop. (Probably the last value will be processed twice.)
The same thing would happen if your loop was while (!in.bad())
, or while (!in.eof())
.
What you really want is to check whether in >> x
succeeded. Nothing else. And the classic way to do that is:
while (in >> x) {
/* If we get here, x has a legitimate value */
...
}
in >> x
just returns in
, so that's exactly equivalent to
while (in >> x, in) {
/* ... */
}
In other words, bool(in)
is false
precisely when the previous operation failed, and true
precisely when it succeeded. That's not the same as in.good()
because we don't (yet) want to test whether EOF was encountered.
in.bad()
doesn't examine the eof flag: in.bad()
being false definitely means that the previous read operation failed.Upvotes: 2
Reputation: 206567
There's an excellent table at http://en.cppreference.com/w/cpp/io/basic_ios/good that explains state of an std::istream
and the values various functions return.
The only time while ( stream.good() )
and while(stream)
will be different is when the contents of stream have been successfully read and EOF has been reached. At that time, stream.good()
returns true
while (bool)stream
evaluates to false.
Upvotes: 3