|
Error Stack
Submitted by |
I have tried, and decided I didn't like, exception handling. I find it
cumbersome and awkward. I have also found, trying to reuse code, and linking
with libraries, and all the rest, that they never quite give me errors back the
way I would like. It depends, in the end, on the application - not the library
- on how it should be reported - logged/printed/message box/html/etc...
Imparticularly, if I use one library, and that uses another, and that reports
an error, I usually find myself writing error handling routines three times the
length of the rest of my code, trying to figure out which library has stored
the error that actually happened so that I can do something with it.
As an experiment, I tried putting a string in each class I wrote, called
ErrorStr, and a function which returned it. Everything returned success/failure
and you could query the error string for the reason. If a function in a library
was returned an error by another function, it would concatenate its version of
the problem with the one returned, so in the end I see everything, ie:
Error loading data : Error loading models : Failed to initialise textures :
file [skin.jpg] not found
That is nice, and more importantly I get it very easily, it is up to me what I
do with it, and it effectively shows me the calling sequence that leads up to
it. However, for a class such as Vec3f, which holds exactly 3 floats, no more
and no less, it doesn't work, and for a class which I have, say, 300 instances
of, its slightly less than efficient.
The next phase, then, was something globally available to everything in the
project - an error class which stores the error, can be added to, and can be
queried for a formatted string. So that libraries can work independantly, but
not tread on each others toes when used together, this is a singleton, not a
global variable.
To make it easier to push errors onto the stack without running off the right
hand edge of your screen, there are also a couple of global helper functions.
ErrorStack.h and ErrorStack.cpp
are all you need. The other stuff is purely an example/test of the class.
I hope someone finds that usefull. It isn't actually intended to be copied as
is - it is a fairly simple design pattern for handling errors and should be
changed to work the way you do (error numbers / string tables / templated
singletons / whatever)
|
Download Associated File: errorstack.txt (5,445 bytes)
//COTD (09/27/2001) submitted by Squint [flipcode@squint.clara.co.uk]
// ErrorStack.h
#ifndef ErrorStack_H
#define ErrorStack_H
////////////////////////////////////////////////////////////////
// Class header for ErrorStack
////////////////////////////////////////////////////////////////
#include <vector>
#include <string>
#include <stdarg.h>
class ErrorStack
{
private:
ErrorStack() {} // Constructor
virtual ~ErrorStack() {} // Destructor
ErrorStack (const ErrorStack &); // Singleton so no copy constructor
ErrorStack & operator= (const ErrorStack &); // Singleton so no assignment operator
protected:
std::vector <std::string> Stack; // This stores the error messages
public:
static class ErrorStack * Instance () { static ErrorStack * TheInstance = 0; if(TheInstance) return TheInstance; else return (TheInstance = new class ErrorStack); }
void Clear(); // This empties the stack
void Push(const char * fmt, ...); // This adds an error message to the stack
void Push(const std::string & str); // This adds an error message to the stack
std::string Report(); // This returns a formatted string of all errors in the stack
};
// These are shortcut functions for the above singleton:
extern void PushError(const char * fmt, ...);
extern void PushError(const std::string & str);
#endif // ErrorStack_H
// ErrorStack.cpp
///////////////////////////////////////////////////////////////////////////////
// Class body for ErrorStack
///////////////////////////////////////////////////////////////////////////////
#include "ErrorStack.h"
#include <stdio.h>
using namespace std;
///////////////////////////////////////////////////////////////////////////////
// Clear:
// Empties the error stack.
// Needs calling if you attempt to continue from an error, which may include
// anywhere you choose to completely ignore one.
///////////////////////////////////////////////////////////////////////////////
void ErrorStack::Clear()
{
Stack.clear();
}
///////////////////////////////////////////////////////////////////////////////
// Push:
// Adds an error message to the stack.
///////////////////////////////////////////////////////////////////////////////
void ErrorStack::Push(const std::string & str)
{
Stack.push_back(str);
}
///////////////////////////////////////////////////////////////////////////////
// Push:
// Adds an error message to the stack.
///////////////////////////////////////////////////////////////////////////////
void ErrorStack::Push(const char *fmt, ...)
{
static char str[8192];
va_list argptr;
va_start(argptr, fmt);
vsprintf(str, fmt, argptr);
va_end(argptr);
Stack.push_back(str);
}
///////////////////////////////////////////////////////////////////////////////
// Report:
// Returns the errors on the stack as a single formatted string.
///////////////////////////////////////////////////////////////////////////////
string ErrorStack::Report()
{
string str;
vector<string>::iterator s;
if(Stack.size())
{
s = Stack.begin();
str = *s++;
while(s != Stack.end())
{
str = *s + " [" + str + "]";
++s;
}
}
else
{
str = "No Error";
}
return(str);
}
///////////////////////////////////////////////////////////////////////////////
// The following functions are global, and exist to simplify the use of the
// error stack:
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PushError:
// Pushes a string onto the error stack.
///////////////////////////////////////////////////////////////////////////////
void PushError(const string & str)
{
ErrorStack::Instance()->Push(str);
}
///////////////////////////////////////////////////////////////////////////////
// PushError:
// Pushes a string, which can include formatting, onto the error stack.
///////////////////////////////////////////////////////////////////////////////
void PushError(const char *fmt, ...)
{
static char str[8192];
va_list argptr;
va_start(argptr, fmt);
vsprintf(str, fmt, argptr);
va_end(argptr);
ErrorStack::Instance()->Push(str);
}
// Example code
#include <stdio.h>
#include "First.h"
#include "ErrorStack.h"
int main(int argc, char **argv)
{
First first;
if(!(first.DoSomething()))
{
PushError("Do something failed");
printf("%s\n", ErrorStack::Instance()->Report().c_str());
exit(0);
}
return(0);
}
#include "Second.h"
class First
{
protected:
Second second;
public:
bool DoSomething();
};
#include "First.h"
#include "ErrorStack.h"
bool First::DoSomething()
{
if(second.DoSomethingElse())
{
return(true);
}
else
{
PushError("Failed to do something else");
return(false);
}
}
class Second
{
public:
bool DoSomethingElse();
};
#include "Second.h"
#include "ErrorStack.h"
bool Second::DoSomethingElse()
{
// This always fails:
PushError("This always fails");
return(false);
}
|
|
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
|