63

A colleague just told me that this code:

std::ifstream stream(filename.c_str());
if (!stream)
{
    throw std::runtime_error("..");
}

would be wrong. He said ifstream evaluates to 0 if opening is successful. My code works, but I wanted to find the documentation but didn't see where it says how to check if opening was successful. Can you point me to it?

honk
  • 9,137
  • 11
  • 75
  • 83
Philipp
  • 11,549
  • 8
  • 66
  • 126

4 Answers4

67

operator! is overloaded for std::ifstream, so you can do this.

In my opinion, though, this is a horrible abuse of operator overloading (by the standards committee). It's much more explicit what you're checking if you just do if (stream.fail()).

tomatopipps
  • 299
  • 2
  • 13
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • 18
    don't forget to check `stream.bad()`, `stream.good()`, `stream.fail()`, and `stream.is_open()`. sigh... – Inverse Nov 17 '10 at 17:15
  • thanks a lot for the link! I agree that it's not nice to do the check using this operator, so I will change it. We wouldn't have had the discussion with if (stream.fail()). – Philipp Nov 17 '10 at 17:18
  • 17
    The ! is overloaded to check 'fail' and 'bad' – Martin Beckett Nov 17 '10 at 17:25
  • @Martin: Yes, `fail()` checks both flags as well. – Oliver Charlesworth Nov 17 '10 at 22:11
  • 9
    There is no "abuse" here. – Lightness Races in Orbit Apr 03 '15 at 18:38
  • 5
    I actually think fail is _more_ ambiguous and/or likely to confuse than the operators, just because it checks both failbit and badbit despite its name. – Useless Apr 05 '15 at 14:24
  • Why is that an abuse? It's a valid operator, c++ supports overloading it, and reading the code using it is pleasant since it gives out - 'if stream is not okay'. – Abhinav Gauniyal Aug 31 '16 at 18:13
  • 4
    @abhinav: because it's (largely) a special snowflake - this (using ! to mean "failed") isn't a universal pattern and so IMO it *decreases* legibility. – Oliver Charlesworth Aug 31 '16 at 18:29
  • 3
    Probably well into bikeshedding territory at this point, but in my opinion, `operator!` is pretty universal to mean "this object is in an invalid state" for any non-trivial class/struct. I personally find that slightly more clear than `.fail()`, which strikes me as a verb at first glance and makes me check the docs to be sure. – GrandOpener Jun 27 '19 at 20:22
14

You can make a particular stream throw an exception on any of eof/fail/bad by calling its ios::exceptions() function with the proper bitmask. So, you could rewrite the example in the initial question above as:

std::ifstream stream;
stream.exceptions(std::ios::failbit | std::ios::badbit);
stream.open(filename.c_str());

Here stream will throw an exception when the failbit or badbit gets set. For example if ifstream::open() fails it will set the failbit and throw an exception. Of course, this will throw an exception later if either of these bits gets set on the stream, so this rewrite is not exactly the same as the initial example. You can call

stream.exceptions(std::ios::goodbit);

to cancel all exceptions on the stream and go back to checking for errors.

Greg Satir
  • 534
  • 3
  • 8
  • Unfortunately this gives an exception at the end of iterating the file... `libc++abi: terminating with uncaught exception of type std::__1::ios_base::failure: ios_base::clear: unspecified iostream_category error` – Hugh Perkins Apr 10 '22 at 13:26
11

You can also use is_open() to check if it worked, but ! is allowed (it's not checking for zero, it's a special overload of ! )

edit:
Just out of interest - why doesn't this throw an exception?
Is it just that streams were introduced before exceptions
or are we into the old C++ thing of - it's only an error not exceptional enough to be an exception.

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • 1
    I'm wondering since 20 years, what the need for the existence of an unsuccessful ifstream object is... Potentially in another 20 years this problem might be solved (by the introduction of another constructor taking an additional please_throw() argument?). Hopefully by this time, the reason for the error will be contained in the exception object. –  Aug 17 '18 at 18:04
5

Your colleague is wrong. Perhaps he's forgotten that you're not writing C.

The code is spot on. It's exactly how you should be checking stream state.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055