Confusing fstream usage and exception handling in C++

This article describes four facts about C++ streams I found confusing or counterintuitive. The last fact talks about correct exception handling when using fstream.

Fact 1

fstream file("filename");

will NOT create new file called “filename” if such a file does not exist. To achieve this goal, one has to use either

ofstream file("filename");

or

fstream file("filename",fstream::out);

Fact 2

ofstream file("filename");

will by default remove all contents of a file called “filename” if such a file exists.

Fact 3

Let us have a function that prints all stream state flags.

void print_state (const std::ios& stream) {
  std::cerr << "good()=" << stream.good();
  std::cerr << " eof()=" << stream.eof();
  std::cerr << " fail()=" << stream.fail();
  std::cerr << " bad()=" << stream.bad();
  std::cerr << endl;
}

Reading from a good stream (goodbit == true) that contains only whitespaces (newline, tabs, spaces, etc.) to a variable will NOT change the variable and no exception occurs.

ofstream out("news");
print_state(out);
out.close();

ifstream in("news");
char c='@';
in>>c;
cout<<c<<endl;
print_state(in);

will print

good()=1 eof()=0 fail()=0 bad()=0
@
good()=0 eof()=1 fail()=1 bad()=0

Note also that the failbit has been set alongside the eofbit. This may bring another issue.

Fact 4

file.exceptions ( std::ifstream::failbit |
                  std::ifstream::badbit );

throws an exception if the stream has any of the flags in the argument (here failbit and badbit) set to true. Usually one opens file this way.

ifstream file;
file.exceptions ( std::ifstream::failbit |
                  std::ifstream::badbit );
try {
    file.open ("test.txt");

This is fine. However, if the programmer will not set the exception mask back to its original value using

ios_base::iostate state = file.exceptions(); //save state
...
file.exceptions(state); //load state

then an unexpected behaviour might occur. For example, if the following code executes with the exception mask not set back to its original value then an exception will occur instead of normal termination of this cycle.

string line;
while (getline(file,line)){ //exception when end of file
...
};

To get back to the normal (default) behaviour, one must set the exception mask back to its original value as previously stated.

Leave a comment