9

Consider the following code:

    ifstream in;
    try {
        in.exceptions ( ifstream::failbit | ifstream::badbit );
        in.open(pConfLocation);
    } catch ( ifstream::failure e ) {
        throw std::runtime_error("Can't open configuration file\n");
    }

    vector<string> lns;
    string s;

    in.clear();
    while ( !in.eof() ){
        getline( in, s );
        boost::algorithm::trim(s);
        lns.push_back( s+='\n');
    }

So:

  1. I set the following "exception mask" ( ifstream::failbit | ifstream::badbit ) for the needs of the try-catch block. The file opens without problems.
  2. In while{} block, I know that at the end of the file eofbit will be set. But

The exception mask is an internal value of all stream objects specifying which state flags have to throw an exception when they are set.

I did NOT set ifstream::eofbit, but anyway the following error appears at runtime:

terminate called after throwing an instance of 'std::ios_base::failure'
  what():  basic_ios::clear
The program has unexpectedly finished.

I cannot understand this behavior. I tried to use in.clear() right before while{} but with no effect. clear() itself sets goodbit, and as far as I understand, "flags have to throw an exception" (see the quote above), but when googbit set it's not causing to throw any exceptions…

If to delete

        in.exceptions ( ifstream::failbit | ifstream::badbit );

it works.


How to make getline() work in this case?

Craig M. Brandenburg
  • 2,624
  • 2
  • 22
  • 33
Razorfever
  • 215
  • 2
  • 3
  • 10

1 Answers1

8

The problem is in your input iteration. eofbit is only set when the last read reached EOF, not if the next read will read only EOF. When the latter happens, failbit is set at the same time. See the discussion here.

In your particular case, if the file ends with a newline (as it probably does), the getline() reads up to and including that newline and returns. eofbit is still not set. The next getline() then encounters EOF directly, and as per its documentation, "If the function extracts no elements, it calls setstate(failbit)."

Community
  • 1
  • 1
Angew is no longer proud of SO
  • 156,801
  • 13
  • 318
  • 412
  • Ok, but I clear()-ed exception mask, why is it still seems to be active? – Razorfever Nov 30 '12 at 19:13
  • 1
    @Razorfever There is no `clean()` member, I assume you meant `clear()`. This clears the state bits (`eofbit`, `failbit` and `badbit`), but does not affect the exception mask. – Angew is no longer proud of SO Nov 30 '12 at 19:50
  • Yes, I used clear() sorry [fixed in Q]. Probably the last one question related to the problem: is there any way to return to state preceding setting of the exception mask? – Razorfever Nov 30 '12 at 20:01
  • @Razorfever I don't understand what you mean now. Do you want to clear the exception mask? If so, you can do `in.exceptions(ifstream::goodbit);` – Angew is no longer proud of SO Nov 30 '12 at 20:11
  • I mean I dont understand why if to remove "in.exceptions ( ifstream::failbit | ifstream::badbit )" there will be no errors visible errors in this code. – Razorfever Nov 30 '12 at 20:15
  • 1
    If the exception is not thrown, the last `getline()` (the one which sets `failbit`) will clear `s` and you'll process an empty string (push `"\n"` into `lns`) which was never part of the input. In other words, you're getting bogus data. – Angew is no longer proud of SO Nov 30 '12 at 20:21
  • 2
    It is worth mentioning the correct loop form to use: `while (getline( in, s )) { boost::algorithm::trim(s); lns.push_back( s+='\n'); }` – Robᵩ Nov 30 '12 at 22:21
  • I met the same problem. I don't quite get how you guys solve the problem while keeping exceptions flags set for `try/catch` block. – RandomEli May 05 '17 at 21:37
  • @LingboTang You have to have a clear idea of what is "reaching EOF" and what is "failure" in stream terminology (I suggest reading some [`iostate` reference](http://en.cppreference.com/w/cpp/io/ios_base/iostate)). If you really want exceptions for failure but not for reading past the last line in a file, you have to use `peek` before reading. – Angew is no longer proud of SO May 06 '17 at 08:02