Why are C++ STL iostreams not "exception friendly"?

C++ExceptionStlIostream

C++ Problem Overview


I'm used to the Delphi VCL Framework, where TStreams throw exceptions on errors (e.g file not found, disk full). I'm porting some code to use C++ STL instead, and have been caught out by iostreams NOT throwing exceptions by default, but setting badbit/failbit flags instead.

Two questions...

a: Why is this - It seems an odd design decision for a language built with exceptions in it from day one?

b: How best to avoid this? I could produce shim classes that throw as I would expect, but this feels like reinventing the wheel. Maybe there's a BOOST library that does this in a saner fashion?

C++ Solutions


Solution 1 - C++

  1. C++ wasn't built with exceptions from day one. "C with classes" started in 1979, and exceptions were added in 1989. Meanwhile, the streams library was written as early as 1984 (later becomes iostreams in 1989 (later reimplemented by GNU in 1991)), it just cannot use exception handling in the beginning.

    Ref:

  2. You can enable exceptions with the .exceptions method.

// ios::exceptions
#include <iostream>
#include <fstream>
#include <string>

int main () {
	std::ifstream file;
	file.exceptions(ifstream::failbit | ifstream::badbit);
	try {
		file.open ("test.txt");
		std::string buf;
		while (std::getline(file, buf))
			std::cout << "Read> " << buf << "\n";
	}
	catch (ifstream::failure& e) {
		std::cout << "Exception opening/reading file\n";
	}
}

Solution 2 - C++

OK, it's "Answer my own question" time...

First, thanks to KennyTM for the history. As he says, C++ was NOT designed with exceptions from day one, so it's unsurprising that iostreams 'exception' handling was bolted on afterwards.

Second, as Neil B points out, having exceptions on input format conversion errors would be a significant pain. This surprised me, because I was considering iostreams as a simple filesystem wrapper layer, and I hadn't considered that case at all.

Third, it appears BOOST does bring something to the party: Boost.IOStreams. If I understand correctly, these handle the low-level I/O and buffering aspect of streams, leaving the regular c++ IOStreams library to handle conversion issues. Boost.IOStreams does use exceptions in the way I'd expect. If I understand it correctly, Kenny's example could also look like this:

#include <ostream>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>

int main () {
  boost::iostreams::stream_buffer <boost::iostreams::file_source> buf("test.txt");
  std::istream file(&buf);

  try {
    std::string buf;
    while (std::getline(file, buf))
      std::cout << "Read> " << buf << "\n";
  }
  catch (std::ios_base::failure::failure e) {
    std::cout << "Exception opening/reading file\n";
  }
  std::cout.flush();

  file.close();

  return 0;
}

I think with this version, things like "file not found" should throw, but 'istream' errors will be reported by badbit/failbit.

Solution 3 - C++

As Kenny says, you can enable exceptions if you want. But normally I/O requires some sort of resumption style of programming when an error occurs, which is not easily supported by using exceptions - testing the state of the stream after an input operation is much simpler. I've never actually seen any C++ code that uses exceptions on I/O.

Solution 4 - C++

  1. Whenever you throw an exception you need to think about exception safety. So no exception, no exception, no exception-safety headache.

  2. Iostreams also support exceptions. But throwing an exception is optional. You can enable exception by setting exceptions (failbit | badbit | eofbit)

  3. Iostreams let you entertain both exception and expection-less behavior.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRoddyView Question on Stackoverflow
Solution 1 - C++kennytmView Answer on Stackoverflow
Solution 2 - C++RoddyView Answer on Stackoverflow
Solution 3 - C++anonView Answer on Stackoverflow
Solution 4 - C++Neel BasuView Answer on Stackoverflow