Exception Handling System

Author:
KinoX
This page will introduce you to the use of the Pro-Vocation handling system.

Exception handling system in C++

C++ Exception Handling system is quite simple. It consists in a guarded section symbolised by a try block, an exception catching sytem symbolised by a catch block and an exception raising mechanism via the throw command. The exception catching mechanism is based on types to differentiate raised exeption and then provide the correct response.

If an exception of type A is raised in a guarded section, then Exception handling system see if there is a corresponding catch for type A at the end of the guarded section. If so the code in the catcher is executed. If not, then the exception is passed to the higher level function and so on until an appropriate catcher is found : this mechanism is called stack unwinding. Notice that during stack unwinding, the destructors of the class allocated on the stack are automatically called.

A typical guarded function may look like this :

 void function1(int arg1)
 {
    string wazaaa("Class allocated on the stack");
    ...
   //Some unguarded code
   ...
   try  //beginning of the guarded section
    {
        //guarded code here
        ...
        if ( something_is_wrong )
            throw "this is a char * type exception";
        ...
        //more guarded code
        ...
    } // End of guarded section
    catch ( char * e )  //char * exception type catcher
    {
        cout << "We just print the exception : " << e << endl;
        //exception was gracefully handled, execution will continue AFTER the last catch block      
    }
   catch (...)  //catch all types of exception not previously catched
   {
        //some clean up code here
        throw;  // we can't handle it, so start stack unwinding
                // wazaaa destructor will be called and execution will continue in next appropriate catch block
    }
    ...
    //some more unguarded code if you want to
    ...
 }

Exception handling is an out of the flow execution. However, if the guarded section installing doesn't cost much, exception handling causes a great execution overhead as the CPU exectuion cache as to be flushed. So exceptions should ONLY be used to handle unexpected errors, likes access failure, etc...

Pro-Vocation Exception Handling System (PV-EHS)

First, to ensure maximum protability, PV-EHS rely entirelly on C++ Exception Handling System. On top of that it introduces some more features, like a history of guarded section traversed during stack unwinding. PV-EHS exclusively use the TracedException base class and provide a set of macros to ease programming.

Basic guarded sections :

First of all, you should use INIT_TRACED_EXCEPTIONS before any exception happen. Especially if you are on windows platform and want to catch system asynchroneous exceptions (divide by zero, wrong memory access, etc...). Otherwise those exceptions will be catched as unknown exceptions. The beginning of main function is a good place to call the INIT_TRACED_EXCEPTIONS. (NB : if you are using microsoft compiler, you have to use the /EHa instead of the /EHs flag)

A guarded section can be easily defined using the TRY_BLOCK_START and TRY_BLOCK_END(x) macros. All the code between this macros will be in the guarded section. On top of that the TRY_BLOCK_END takes the name of the guarded section as a parameter. Usually it's the name of the function which the guarded section blongs to. Such a guarded section catch by default all exceptions of type std::exception and TracedException. The default behavior for std::exception type is to throw TracedException constructes from it. The default behavior for TracedException type is to log the name of the guarded section and then start unwinding the stack.

Remember that the unwinding history only get the names of guarded sections the exception pass through. If some function lacks of guarded section, they will *NOT* be referenced.

You may also want only to use default catcher. For this, use the macro CATCH_TRACED_EXCEPTION(SectionName) just after a try block.

Throwing exceptions :

Some macros are also provided in order to throw TracedException easily. These Macros are :

User defined exceptions :

You may not always want to unwind the stack until the program exits. For this you can catch user defined exceptions using the CATCH_CUSTOM_EXCEPTION(x) macro jsut before an TRY_BLOCK_END. The parameter x is the type of the exception you want to catch. Code to handle the exception follows immediatly the macro, and you may chain as many CATCH_CUSTOM_EXCEPTION as you want.

In general it's better to use a class derived from TracedException as type filter in order to keep the guarded section history, but you may use any other types as well.

Retrieving exception reason and guarded section stack :

You mays retrieve the reason that caused the exception using either TracedException::GetReason (returns const std::string &) or TracedException::what (returns const char *). The Guarded section stack is kept as a string where names are separated using the "->" symbol. You may retrieve it using TracedException::GetClassStack.

Example :

Eventually a small example to illustrate what is said above.

 class MyException : public TracedException;

 int f1(const char * arg1)
 {
    TRY_BLOCK_START
    ...
    if(arg1_is_malformed)
        THROW_TRACED_FMT_EXCEPTION("Error %d : String %s is malformed", 32 % arg1 );
    ...
    TRY_BLOCK_START

        if ( OpenTheFile(arg1) )
            throw MyException("File not found");
        ...
    CATCH_CUSTOM_EXCEPTION(MyException& e)
        // do some clean up here
        throw;  // pass the exception to the next handler. This is not mandatory
    TRY_BLOCK_END("File Opening");
    ...
    // some code to imlement the function
    ...
    TRY_BLOCK_END("f1");
    
    return false;
 }

 int main(in argc, char * argv[])
 {
    INIT_TRACED_EXCEPTIONS;

    try
    {
        f1(argv[1]);
    }
    catch(TracedException e)
    {
        cerr << "Catched exception " << e.GetReason() << endl;
        cerr << "In function " <<  e.GetClassStack() << endl;
    }
    catch(...)
    {
        cerr << "UnHandled exception raised" << endl;
    }
    return 0;
 }

Generated on Sun Jan 17 11:39:25 2010 for PVLE (Pro-Vocation Light Engine) by  doxygen 1.5.9