ios::eofbit
ios::failbit
ios::badbit
ios::goodbit
: not really a bit—just the absence of the other bits.
ios::eofbit
ios::eofbit
is set when end-of-file is encountered.
That’s when you try to read, but can’t, because there’s no more data. It doesn’t predict.
ifstream in("/dev/null"); if (in.rdstate() & ios::eofbit) cout << "Before, eofbit\n"; if (in.rdstate() & ios::failbit) cout << "Before, failbit\n"; if (in.rdstate() & ios::badbit) cout << "Before, badbit\n"; char c; in.get(c); if (in.rdstate() & ios::eofbit) cout << "After, eofbit\n"; if (in.rdstate() & ios::failbit) cout << "After, failbit\n"; if (in.rdstate() & ios::badbit) cout << "After, badbit\n";
After, eofbit After, failbit
ios::failbit
ios::failbit
is set when an I/O operation fails—you didn’t
get what you asked for.
ios::failbit
was set in the previous example, because we
tried to read a character, and couldn’t.
double
from /etc/resolv.conf
,
which does not contain numbers:
ifstream in("/etc/resolv.conf"); if (in.rdstate() & ios::eofbit) cout << "Before, eofbit\n"; if (in.rdstate() & ios::failbit) cout << "Before, failbit\n"; if (in.rdstate() & ios::badbit) cout << "Before, badbit\n"; double d; in >> d; if (in.rdstate() & ios::eofbit) cout << "After, eofbit\n"; if (in.rdstate() & ios::failbit) cout << "After, failbit\n"; if (in.rdstate() & ios::badbit) cout << "After, badbit\n";
After, failbit
ios::failbit
upon open failureAlso, ios::failbit
is set when a file can’t be opened.
ifstream in("/this/file/doesn’t/exist"); if (in.rdstate() & ios::eofbit) cout << "eofbit\n"; if (in.rdstate() & ios::failbit) cout << "failbit\n"; if (in.rdstate() & ios::badbit) cout << "badbit\n";
failbit
ios::badbit
ios::badbit
is not set upon a mere conversion error,
but, rather, when a low-level I/O error occurs:
the system runs out of memory, the disk becomes full, etc.
/dev/full
, which simulates a
disk that is always full.
ofstream out("/dev/full"); if (out.rdstate() & ios::eofbit) cout << "Before, eofbit\n"; if (out.rdstate() & ios::failbit) cout << "Before, failbit\n"; if (out.rdstate() & ios::badbit) cout << "Before, badbit\n"; out << "foo" << endl; if (out.rdstate() & ios::eofbit) cout << "After, eofbit\n"; if (out.rdstate() & ios::failbit) cout << "After, failbit\n"; if (out.rdstate() & ios::badbit) cout << "After, badbit\n";
After, badbit
ifstream in("/etc/resolv.conf"); double d; in >> d; if (in.rdstate() & ios::failbit) cout << "#1: failbit\n"; char c; in >> c; if (in.rdstate() & ios::failbit) cout << "#2: failbit\n";
#1: failbit #2: failbit
ios::failbit
is set, it stays set.
ios::failbit
is set.
ifstream in("/etc/resolv.conf"); double d; in >> d; if (in.rdstate() & ios::failbit) cout << "#1: failbit\n"; char c; in >> c; if (in.rdstate() & ios::failbit) cout << "#2: failbit\n"; in.clear(); in >> c; if (in.rdstate() & ios::failbit) cout << "#3: failbit\n"; cout << "c=‘" << c << "’\n";
#1: failbit #2: failbit c=‘s’
«ios::clear(cpp)» clears ios::badbit
, ios::eofbit
,
and ios::failbit
.
The previous slides have been interrogating the bits in a straightforward, but clumsy fashion. There are several other ways:
How | Results |
---|---|
stream.rdstate() | ios::eofbit|ios::badbit|ios::failbit |
stream.good() | no bits are set |
stream.eof() | ios::eofbit is set |
stream.bad() | ios::badbit is set |
stream.fail() | ios::badbit|ios::failbit (!) |
! stream | .fail() |
stream in boolean context | ! .fail() |
I generally only use boolean context, and occasionally .eof()
when
I want to be rigorous. I also avoid .is_open()
:
ifstream in("/etc/resolv.conf"); if (!in) { cerr << "Can’t open /etc/resolv.conf for reading\n"; return 1; } float f; while (in >> f) cout << "Hooray, got a number: " << f << '\n'; // All done reading. Why did we stop? if (!in.eof()) cerr << "Error!\n";
Error!