Reputation: 51
I was playing around with istream iterators and exception handling a few days ago and I came across with this curiousity:
#include <iostream>
#include <fstream>
#include <iterator>
#include <algorithm>
using namespace std;
int main(int argc, char* argv[])
{
if (argc < 2) {
cout << argv[0] << " <file>" << endl;
return -1;
}
try {
ifstream ifs(argv[1]);
ifs.exceptions(ios::failbit | ios::badbit);
istream_iterator<string> iss(ifs), iss_end;
copy(iss, iss_end, ostream_iterator<string>(cout, "\n"));
}
catch (const ios_base::failure& e) {
cerr << e.what() << endl;
return -2;
}
return 0;
}
Why a failbit exception is always raised after reading the last word of the input file?
Upvotes: 5
Views: 1675
Reputation: 14516
failbit
is set whenever a read operation fails to extract any characters, whether this is because it hit EOF or not.
stringstream ss ("foo");
string s;
int i;
ss >> i; // sets failbit because there is no number in the stream
ss.clear();
ss >> s; // sets eofbit because EOF is hit
ss.clear();
ss >> s; // sets eofbit and failbit because EOF is hit and nothing is extracted.
Upvotes: 4
Reputation: 41331
Good question. It would be nice to be able to catch other failures in that call, but have it continue normally when it hits eof.
That said, I haven't used exceptions with streams before. I think you could do the copy and check the state of the stream afterwards to detect other errors, for example:
ifstream ifs(argv[1]);
if (!ifs) {
cerr << "Couldn't open " << argv[1] << '\n';
return -1;
}
//ifs.exceptions(ios::failbit | ios::badbit);
istream_iterator<std::string> iss(ifs), iss_end;
copy(iss, iss_end, ostream_iterator<std::string>(cout, "\n"));
if (!ifs.eof()) {
cerr << "Failed to read the entire file.\n";
return -2;
}
Upvotes: 1
Reputation: 52284
One detect the EOF condition by reading until a failure -- which triggers the exception -- and then checking the cause of the failure.
To expand: the istream_iterator becomes invalid when after having read a value with >>, the stream operator void* returns NULL. But for that, the operator >> has to set the fail bit, so raise the exception.
Upvotes: 0