Skip to main content.
August 29th, 2005

Levigating the wheel - Error handling

I’m all for standards, but there are different kinds of standardization. When it comes to C++, the language details is clearly standardized. It’s usage is not.
This weekend I spent some time with error handling. Error handling is really painful and makes code look ugly. When I started programming several years ago, resources were tight. There was no virtual memory and no hard-disks. Errors were common and they had to be dealt with carefully.
Nowadays I think that the error checking is generally more lax. However, my paranoia about the worst case scenarios isn’t going away anytime soon.

There are several ways to deal with errors. C++ notably brings the concept of exception handling. I’ve been reading about that but I didn’t come out very convinced. It seems like one of those things a bit too complicated to be used in everyday programming. Up to now, my choice of error handling has been to return errors with return values, and to use goto as a way to quickly escape from a function.

//------------------------kerror myfunction(){    if ( problem )        goto exiterr;

    // …    return 0;

exiterr:    // free anything if necessary    return -1;}

//————————if ( myfunction() < 0 )    puts( “Error !” );

Additionally, to make sure that errors aren’t forgotten at debug time, I put an assert. Actually, I have a macro that will assert and finally go to the end of the function.

//------------------------kerror myfunction(){    // if a problem occurs, do an assert(0) and goto exiterr    TRAP_ERR( problem );    // …    return 0;

exiterr:    return -1;}

However, this means that I have to keep track constantly of every possible returned error value. Plus, most return values are dedicated to error handling (with some exceptions for when a pointer is returned, where NULL means error).

My latest experiment is with error values as states. Basically a class has an item dedicated to be an error value. Leaving the return value to more intuitive purposes, such as a value read from a file, or a boolean to express success or failure.
Because the error is an internal state of the class, then it can be queried at any time, without having to check at every function.
So here it goes:

//------------------------class MyClass{    int     value;    kerror  error;public:    kerror  GetError() { return error };    int     ReadIntValue();};

//————————MyClass    yoyo;

    a = yoyo.ReadIntValue();    b = yoyo.ReadIntValue();    c = yoyo.ReadIntValue();

    if ( yoyo.GetError() )        puts( “Got an error somewhere while reading !” );

This is how the interface goes.
As far as implementing it. I’ve made some macros here too. On failure, the TRAP_ERR macro, this time sets an error value into the error member of the class. Then it exits from the function.
I’ve also tried to avoid the goto thing. TRAP_ERR simply returns false/0 in case the function has a return value. This doesn’t allow me to have a portion of the code where I can unwind the function (free resources). Possibly a problem, but time will tell, for now I’d rather avoid to have an exiterr label at the end of every function. And now my functions can look a bit nicer:

//------------------------bool MyClass::DoSomething(){    // asserts and returns false    TRAP_ERR( problem );

    // …

    return true;}

Posted by Davide Pasca in Uncategorized

This entry was posted on Monday, August 29th, 2005 at 1:40 am and is filed under Uncategorized. You can follow any responses to this entry through the comments RSS 2.0 feed. You can leave a response, or trackback from your own site.

2 Responses to “Levigating the wheel - Error handling”

  1. Rince says:

    We use assert for catching errors since in most cases you probably dont want to carry on with the execution if error is encountered. standar c assert( ) only works in debug builds so we have:

    #define ASSERT(x) if(!(x)) { DebugAssertFail(#x, __FILE__, __LINE__); asm(”breakc 0″); };

    and then:

    void DebugAssertFail(const char *pExpression, const char *pFileString, int LineNumber)
    {
    char temp[256];
    sprintf(temp, “assert failed: %s, %s, %d\n”, pExpression, pFileString, LineNumber);
    printf(temp);

    }

  2. Davide Pasca says:

    I guess that generally in a game there isn’t really much need for fault tollerance. It’s mostly a problem with applications.. but unfortunately it’s also a problem with network gaming.. where one must be ready to handle all sort of connection issues.
    Facking Internet !

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>