17. Fault Handling

Rec. 60
Make sure that fault handling is done so that the transfer to exception handling (when this is available in C++) may be easily made.
Rec. 61
Check the fault codes which may be received from library functions even if these functions seem foolproof.

In November 1990, the ANSI C++ committee accepted a proposal for exception handling which is described in chapter 15 of The Annotated C++ Reference Manual. When designing fault handling in code, it is appropriate to consider being able to make a smooth transfer to exception handling. For example, instead of using ordinary fault codes, which may necessitate a lot of re-programming when exception handling is available, a call can be made to a function void fault(const char*)which sends a fault message (somewhere) and then terminates execution in some way.

System functions (those which are specific to UNIX) ought to be used with care if the code is to be portable. If such functions are used, the possible fault codes that may be received should be carefully checked.

Two important characteristics of a robust system are that all faults are reported and, if the fault is so serious that continued execution is not possible, the process is terminated. In this way, the propagation of faults through the system is avoided. It is better to have a process crash, than to spread erroneous information to other processes. In achieving this goal, it is important to always test fault codes from library functions. The opening or closing of files may fail, allocation of data may fail, etc. One test too many is better than one test too few. Our own functions should preferably not return fault codes, but should instead take advantage of exception handling.

Example 66: Future exception handling in C++

   // The top function where we catch exceptions thrown in called functions
   int f()
      // We suspect that something can go wrong when function g() is called.
      // Therefore, we enclose the call in a try block.
         return g();       // This is the try block
      // If any exceptions, having a given type, were thrown when g()
      // was executing, they are caught in these two catch blocks.
      catch ( int x )      // catches int
         cerr << "Number " << x << " happened !" << endl;
         return x;
      catch ( char* x )    // catches char*
         // Respond in some other way
      // Anything else that is thrown, is thrown up to the function that calls f()
   // This function has no try or catch block. When the exception is thrown
   // in function h(), it is thrown up to the function f().
   int g()
      return h();
   extern int somethingIsVeryWrongAndICannotHandleThisAnyMore();
   int h()
      // Here we find out that something went wrong, and throw an exception
      if (somethingIsVeryWrongAndICannotHandleThisAnyMore())
         // In this case, we throw an int as exception, but almost any object
         // can be thrown. See Errata for "The Annotated C++ Reference Manual"
         // section 15.7>.
         throw 2;
      // Keep on trucking if all is OK