Distinguishing between failure and end of file in read loop

Posted by celtschk on Stack Overflow See other posts from Stack Overflow or by celtschk
Published on 2011-11-11T22:35:13Z Indexed on 2011/11/12 1:51 UTC
Read the original article Hit count: 196

Filed under:
|
|

The idiomatic loop to read from an istream is

while (thestream >> value)
{
  // do something with value
}

Now this loop has one problem: It will not distinguish if the loop terminated due to end of file, or due to an error. For example, take the following test program:

#include <iostream>
#include <sstream>

void readbools(std::istream& is)
{
  bool b;
  while (is >> b)
  {
    std::cout << (b ? "T" : "F");
  }
  std::cout << " - " << is.good() << is.eof() << is.fail() << is.bad() << "\n";
}

void testread(std::string s)
{
  std::istringstream is(s);
  is >> std::boolalpha;
  readbools(is);
}

int main()
{
  testread("true false");
  testread("true false tr");
}

The first call to testread contains two valid bools, and therefore is not an error. The second call ends with a third, incomplete bool, and therefore is an error. Nevertheless, the behaviour of both is the same. In the first case, reading the boolean value fails because there is none, while in the second case it fails because it is incomplete, and in both cases EOF is hit. Indeed, the program above outputs twice the same line:

TF - 0110
TF - 0110

To solve this problem, I thought of the following solution:

while (thestream >> std::ws && !thestream.eof() && thestream >> value)
{
  // do something with value
}

The idea is to detect regular EOF before actually trying to extract the value. Because there might be whitespace at the end of the file (which would not be an error, but cause read of the last item to not hit EOF), I first discard any whitespace (which cannot fail) and then test for EOF. Only if I'm not at the end of file, I try to read the value.

For my example program, it indeed seems to work, and I get

TF - 0100
TF - 0110

So in the first case (correct input), fail() returns false.

Now my question: Is this solution guaranteed to work, or was I just (un-)lucky that it happened to give the desired result? Also: Is there a simpler (or, if my solution is wrong, a correct) way to get the desired result?

© Stack Overflow or respective owner

Related posts about c++

Related posts about error-handling