Exceptions are a necessary part of the C++ language, but for most programmers they are worse than worthless - they are unusable. When exceptions were first added to the language back in the days before standardization, they were seen as a brilliant improvement over the hideous setjmp/longjmp facility from ANSI C. Because exceptions unwind the stack when they are thrown, they call destructors and clean up all of your untidy messes as they go.

Tom Cargill

It didn't take long for somebody to notice that the emperor had no clothes. In 1994, Tom Cargill published a prescient article in the late C++ Report. Tom pointed out in detail just how difficult it was to write code that actually held up when exceptions were used. Scott Meyers flags this as one of his five Most Important C++ Non-Book Publications...Ever. (Incidentally, Tom is responsible for a piece of wisdom that sounds like a an offhand quip: the ninety-ninety rule. Any project manager who doesn't understand this rule all the way into his or her bones needs to quit. Now.)

The intervening years have not been kind to exceptions. The problems Tom foresaw in 1994 were real, and while they can be managed, writing exception-safe code is still fraught with peril. As a result, exceptions are basically unused by by most C++ programmers. After all, we have to deal with tough problems like writing safe multithreaded apps, understanding template metaprogramming, and dealing with the language's high-maintenance memory management. The last thing we need is to make use of a feature, that while useful, is basically impossible to use correctly.

Naturally, after this rather verbose introduction, you have probably guessed that I'm using this article to tell you about a simple little utility class I use to help me throw informative, easy to build exceptions in my C++ programs. Yes, exceptions are problematic, but there's one place I can use them with impunity: to cause a fatal error that aborts my program.

Fatal Errors Considered Exceptional

If you analyze Tom Cargill's article, or look into any of the additional work that has been done on exceptions up until today, you'll see that most of the nasty side effects are only a problem for a program that tries to keep running in a predictable and safe fashion while throwing and catching exceptions.

The side effects of code that isn't quite exception-safe include memory leaks, partially constructed objects, and invalid containers. All bad things. But the one place they usually don't matter to me is when things have degraded in my program to the point where I'm ready to throw in the towel anyway. That point is when I've encountered a fatal error and am aborting the program. At that point, I throw an exception, which generally percolates all the way up to main(), where it is caught, and error message is printed, and the program exits.

Handling fatal errors this way makes for much cleaner code. I generally assume that every method or function called in my program succeeds, and don't worry about creating special returns with error codes. I blithely march through call after call without checking results, secure in the knowledge that my code is working properly. I know this is the case, because if something went wrong, an exception would have been thrown, and my program would abort.

This error handling strategy is implemented entirely in main(), which generally follows this form in one of my programs:

  1. int main( int argc, char *argv[] )
  2. {
  3.     try {
  4.     //
  5.     // all the work is enclosed in this try block
  6.     //
  7.     ...
  8.     }
  9.     catch ( const std::exception & e )
  10.         std::cout <<"\nFatal error: " <<e.what() <<"\n\n";
  11.         std::cout <<"Hit enter to continue...";
  12.         std::string temp;
  13.         std::getline( std::cin, temp );
  14.         return -1;
  15.     }
  16.     return 0;
  17. }

There are a couple of interesting points to note about the error handler you see here. First, because I am catching std::exception, I will catch any errors in the standard library, such as bad_alloc, logic_error, runtime_error, etc. It's a good idea to have a top-level try/catch block for these items anyway, so my use of exceptions for fatal errors forces good hygiene practices.

Second, I'm using the what() method to give human-readable feedback on exactly what happened to send my program off the rails. This method is defined as virtual for the base class std::exception, so all derived classes will support it. There's no requirement that they populate this string with great prose, but we can at least expect implementors to provide something informative here.

My Exception Class

When I first started using exceptions for fatal errors, I kept things simple by just throwing instances of std::runtime_error when I wanted to abort my program. I could pass the constructor of this object a descriptive string as it was constructed, and that same string would be returned when what() was called in the exception handler. Typical usage might look like this:

  1. #include <stdexcept>
  3. int main( int argc, char *argv[] )
  4. {
  5.     try {
  6.         if ( argc <2 )
  7.             throw std::runtime_error(
  8.                 "Usage:\n\n"
  9.                 "add_link_error url\n" );

This code ensures that if the user leaves off the necessary command line argument, the catch() block will print out a usage statement and return an error value to the invoking shell, which is just what we want. I manage to handle faulty input with just one line of code, don't have to set any error variables, no if/then/break clause to print an error and then exit. It's tidy and works well.

Of course, it wasn't long until I ran into situations where I wanted to provide the user a little more information with a fatal error - information that had to be formatted at runtime. I ended up writing a lot of code that looked like this:

  1. FILE *fp = fopen( "database.txt",
  2.                    "r" );
  3. if ( !fp ) {
  4.     std::stringstream s;
  5.     s <<"Error opening file, errno value of "
  6.       <<errno
  7.       <<" translates to "
  8.       <<strerror( errno );
  9.     throw std::runtime_error( s.str() );
  10. };

This more or less worked, but it added a lot of lines to the code, and as a rule, the fewer lines, the less typing, the more I like it. In this case I have to construct a separate std::stringstream object to hold the formatted error message (or a character buffer if I choose to go old school and use vnsprintf() , a second line to do the formatting, and a third line to construct and throw the exception.

In addition to writing three lines instead of one, I now have to enclose the whole thing in brackets, because the clause following the if statement is multiple lines, which makes the whole thing require five lines of code instead of one!

A Better Way

I needed to find a better way to do this. I first dabbled with a class derived from std::exception that used vnsprintf() to format arguments, C-style. But there were a few disadvantages to this, the primary one being that it made it hard to take advantage of classes that have their own overrides to stream classes. In other words, if I've bothered to create a stream override so I can print the contents of class foo, it's easy to write that to a stream, but not so easy to insert it into a buffer being formatted with vnsprintf().

So I determined that I wanted to have a class that that let me rewrite the code shown above so that it all fits on one line, like this:

  1. FILE *fp = fopen( "database.txt",
  2.                    "r" );
  3. if ( !fp )
  4.     throw fatal_error() <<"Error opening file, errno value of "
  5.                         <<errno
  6.                         <<" translates to "
  7.                         <<strerror( error );

My Goal For Use of class fatal_error

My first stab at getting this to work was to create a class that used multiple inheritance to create a class that inherits from both std::exception and std::stringstream:

  1. class fatal_error
  2.     : public std::exception
  3.     , public std::stringstream
  4. {
  5. ...

With this routine I'd just need to override the definition of what() and I would be in business.

But there was a fatal flaw in this problem: the absence of a copy constructor for std::stringstream. I had assumed that the copy constructor wouldn't be needed, as I was catching the exception object by reference. My thought was that the compiler would create a temporary object, pass it along to my catch clause, and all would be well.

No such luck. In this case, the compiler has the right to make a copy, and even if it doesn't make a copy, it has the right to insist on a copy constructor even if it is only considering the possibility of making a copy. Strike one.

This One Works

So I needed to make a version of my fatal_error class that doesn't try to call the copy constructor for std::stringstream. This is accomplished easily enough by using composition instead of inheritance:

  1. class fatal_error
  2.     : public std::exception
  3. {
  4. ...
  5. private :
  6.     mutable std::stringstream mStream;
  7. };

This solves one problem, but creates another. Because fatal_error is no longer derived from std::stringstream, I've lost the overloaded operators that insert text into the object before it is thrown. In other words, my wished-for code shown above won't compile.

In this case, the solution is simple, I just add a template method to the class:

  1. class fatal_error
  2.     : public std::exception
  3. {
  4. public :
  5.     template<typename T>
  6.     fatal_error& operator<<( const T& t )
  7.     {
  8.         mStream <<t;
  9.         return *this;
  10.      }
  11. ...
  12. }

Now the template class takes care of routing the stream insertion output into the std::stringstream member I've incorporated into my class. Note also that the overloaded insertion operator returns a reference to the fatal_error object, allowing me to chain insertions.

Almost Done

There only two more issues to deal with in order for this class to be ready for use. First, I need to deal with the possibility of a copy constructor being called as this exception is thrown. Because I can't copy the std::stringstream object from the old object to the new, I have to save off its contents into a mutable std::string member called mWhat. The result looks like this:

  1. fatal_error::fatal_error( const fatal_error &that )
  2. {
  3.     mWhat += that.mStream.str();
  4. }

Finally, I need a good version of what() that conforms to what is expected for std::exception. This is nice and easy:

  1. virtual const char *fatalError::what() const throw()
  2. {
  3.     if ( mStream.str().size() ) {
  4.         mWhat += mStream.str();
  5.         mStream.str( "" );
  6.     }
  7.     return mWhat.c_str();
  8. }

Wrapped Up

With that, I have an exception that I can use to easily generate fatal error exceptions with as much data as I want. I only have to include a single header file in any code that uses the class, and I can create and throw the exception in a single line of code, which adheres to the C ideologoy of minimal typing.

Life is good.

Complete source code from the single file, fatal_error.h, is given below. This code should work in g++ 3.x code, and Visual Studio 2003 and 2005 programs. If you run into problems with different versions of various compilers, please let me know!

  1. //
  2. // fatal_error.h
  3. //
  4. #include <sstream>
  5. #include <stdexcept>
  6. #include <string>
  8. //
  9. // This class is designed to make it a little easier
  10. // to throw informative exceptions. It's a little lame,
  11. // but I do like to be able to write code like this
  12. // for fatal errors:
  13. //
  14. // throw fatal_error() <<"Game over, "
  15. //                     <<mHealth
  16. //                     <<" health points!";
  17. //
  18. // It works everywhere I've tested it, let's hope that it holds up.
  19. //
  21. class fatal_error : public std::exception
  22. {
  23. public :
  24.     fatal_error() {};
  25.     //
  26.     // Need a copy constructor, because the runtime of the compiler is
  27.     // allowed to insist on it when it throws an object of this type,
  28.     // even if it doesn't actually make a copy. When I make a copy, I
  29.     // need to capture whatever is in the stringstream object. Note:
  30.     // in many cases, attempting to copy an iostream object leads to
  31.     // errors, so the copy constructor here constructs a brand new
  32.     // mstream object.
  33.     //
  34.     fatal_error( const fatal_error &that )
  35.     {
  36.         mWhat += that.mStream.str();
  37.     }
  38.     //
  39.     // Virtual dtor needed? Not really, but here it is anyway.
  40.     //
  41.     virtual ~fatal_error() throw(){};
  42.     //
  43.     // When I finally get this object to an exception handler,
  44.     // (hopefully catching by reference) I want to display the error
  45.     // message that I've inserted. To do that, I just chapture
  46.     // whatever is in the mWhat string object concatenated
  47.     // with anything that might be in the stringstring mStream object,
  48.     // and return it. (Odds are that only one of them will contain
  49.     // anything, depending on whether or not the copy constructor
  50.     // was called.
  51.     //
  52.     virtual const char *what() const throw()
  53.     {
  54.         if ( mStream.str().size() ) {
  55.             mWhat += mStream.str();
  56.             mStream.str( "" );
  57.         }
  58.         return mWhat.c_str();
  59.     }
  60.     //
  61.     // The template function used to create insertion operators for all
  62.     // of the various types of objects one might insert into this guy.
  63.     //
  64.     template<typename T>
  65.     fatal_error& operator<<( const T& t )
  66.     {
  67.         mStream <<t;
  68.         return *this;
  69.      }
  70. private:
  71.    mutable std::stringstream mStream;
  72.    mutable std::string mWhat;
  73. };