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
