15.3 LINT Exceptions

Team-Fly

15.3 LINT Exceptions

The exception mechanism of C++ is an instrument that is easier to utilize and thereby more effective for error handling than the methods offered by C. The error routine LINT::panic() described previously is limited to the output of error messages and the controlled termination of a program. In general, we are less interested in the division function in which a division by zero has occurred than the function that has called the division and thereby precipitated the error, information that LINT::panic() does not contain and thus cannot pass along. In particular, it is impossible with LINT::panic() to return to this function in order to remove an error there or to react in a way specific to the function. Such possibilities, on the other hand, are offered by the exception mechanism of C++, and we would like here to create the conditions that will make this mechanism usable for the LINT class.

Exceptions in C++ are based principally on three types of constructs: the try block, the catch block, and the instruction throw, by means of which a function signals an error. The first, the catch block, has the function of a local error-handling routine for the try block: Errors that occur within a try block and are announced by means of throw will be caught by the catch block, which follows the try block. Further instructions of the try block are then ignored. The type of error is indicated by the value of the throw instruction as parameter of the accompanying expression.

The connection between try and catch blocks can be sketched as follows:

   try     {        ... // If an error is signaled within an operation with        ... // throw, then it can be        ... // caught by the following catch block.     }    ...   catch (argument)     {        ... // here follows the error handling routine.     } 

If an error does not occur directly within a try block but in a function that is called from there, then this function is terminated, and control is returned to the calling function until, by following the chain of calls in reverse order, a function within a try block is reached. From there control is passed to the appropriate catch block. If no try block is found, then the generic error routine appended by the compiler is called, which then terminates the program, usually with some nonspecific output.

It is clear what the errors are in the LINT class, and it would be a simple possibility to call throw with the error codes, which are provided to the panic() routine by the LINT functions and operators. However, the following solution offers a bit more comfort: We define an abstract base class

   class LINT_Error   {     public:       char* function;       int argno, lineno;       virtual void debug_print (void) const = 0; // pure virtual       virtual LINT_Error() {};   }; 

as well as classes of the following type that build on it:

   // division by zero   class LINT_DivByZero : public LINT_Error   {     public:       LINT_DivByZero (const char* const func, const int line);       void debug_print (void) const;   };   LINT_DivByZero::LINT_DivByZero (const char* const func, const int line)   {     function = func;     lineno = line;     argno = 0;   }   void LINT_DivByZero::debug_print (void) const   {     cerr << "LINT-Exception:" << endl;     cerr << "division by zero in function "            << function << endl;     cerr << "module: " << __FILE__ << ", line: "            << lineno << endl;   } 

For every type of error there exists such a class that like the example shown here can be used with

   throw LINT_DivByZero(function, line); 

to report this particular error. Altogether, the following subclasses of the base class LINT_Error are defined:

   class LINT_Base : public LINT_Error // invalid basis   { ... };   class LINT_DivByZero : public LINT_Error // division by zero   { ... };   class LINT_EMod : public LINT_Error // even modulus for mexpkm   { ... };   class LINT_File : public LINT_Error // error with file I/O   { ... };   class LINT_Heap : public LINT_Error // heap error with new   { ... };   class LINT_Init : public LINT_Error // function argument illegal or uninitialized   { ... };   class LINT_Nullptr : public LINT_Error // null pointer passed as argument   { ... };   class LINT_OFL : public LINT_Error // overflow in function   { ... };   class LINT_UFL : public LINT_Error // underflow in function   { ... }; 

With this we are in a position, on the one hand, to catch LINT errors without distinguishing specifically which error has occurred by inserting a catch block

   catch (LINT_Error const &err) // notice: LINT_Error is abstract     {       // ...       err.debug_print();       // ...     } 

after a try block, while on the other hand we can carry on a goal-directed search for an individual error by specifying the appropriate error class as argument in the catch instruction.

One should note that as an abstract base class LINT_Error is not instantiatable as an object, for which reason the argument err can be passed only by reference and not by value. Although all the LINT functions have been equipped with the panic() instruction for error handling, the use of exceptions does not mean that we must alter all the functions. Rather, we integrate the appropriate throw instructions into the panic() routine, where they are called in conjunction with the error that has been reported. Control is then transferred to the catch block, which belongs to the try block of the calling function. The following code segment of the function panic() clarifies the modus operandi:

   void LINT::panic (LINT_ERRORS error, const char const * func,               const int arg, const int line)   {     if (LINT_User_Error_Handler)       {          LINT_User_Error_Handler (error, func, arg, line);       }     else       {          cerr << "critical run-time error detected by the                            class LINT:\n";          switch (error)            {               case E_LINT_DBZ:                 cerr << "division by zero, operator/function "                   << func << ", line " << line << endl;   #ifdef LINT_EX                 throw LINT_DivByZero (func, line);   #endif                 break;                 // ...            }       }   } 

The behavior that results in the case of an error can be completely controlled by user-defined routines for error handling without the necessity of intervention into the LINT implementation. Moreover, the exception handling can be completely turned off, which is necessary when this mechanism is not supported by a C++ compiler that is to be used. In the case of the present panic() function the exceptions must be turned on explicitly via the definition of the macro LINT_EX, such as with the compiler option -DLINT_EX. Some compilers require the specification of additional options for exception handling to be activated.

To close, we present a small demonstration of the LINT exceptions:

   #include "flintpp.h"    main(void)   {     LINT a = 1, b = 0;     try       {          b = a / b;// error: division by 0       }     catch (LINT_DivByZero error) // error handling for                                    // division by 0          error.debug_print ();          cerr << "division by zero in the module" << __FILE__               << ", line " << __LINE__;       }   } 

Translated with GNU gcc by a call to

   gcc -fhandle-exceptions -DLINT_EX divex.cpp flintpp.cpp flint.c -lstdc++ 

the program produces, in addition to the error message of the function panic(), the following output:

   LINT-Exception:   division by zero in operator/function /   module: flintpp.cpp, line: 402   division by zero in module divex.cpp, line 17 

The significant difference between this and standard error handling without exceptions is that we discover by means of the catch routine where the error was actually caused, namely in line 17 of the module divex.cpp, even though it was discovered somewhere else entirely, namely in the module flintpp.cpp. For debugging large programs this is an extremely helpful source of information.


Team-Fly


Cryptography in C and C++
Cryptography in C and C++
ISBN: 189311595X
EAN: 2147483647
Year: 2001
Pages: 127

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net