Error handling: Opinions?
By the way, the STL class auto_ptr simplifies destroying dynamic objects
quote: Original post by Countach
Cel, have you heard of the phenomena called ''stack unwinding''?
Consider:void Class::loadTexture(File &file){ Texture texture; if(texture.load(file) == ERROR_VALUE){ throw TextureLoadFailedException("Couldn''t load texture"); }}
When an exception occurs all local objects are destroyed in the reverse order of creation. That being the case, no memory leaks will be caused by the exception in the example above.
For dynamic objects (pointers to objects) you need to do something like this:void Class::loadTexture(File &file){ Texture *texture = new Texture(); try { if(texture->load(file) == ERROR_VALUE){ throw TextureLoadFailedException("Couldn''t load texture"); } // other stuff } catch(Exception &exception){ delete texture; // release memory throw; // continue exception }}
IMO that''s a bad way of handling exception handling. You are going to be littering your code with try catches and duplicating cleanup code. A proper exception architecture shouldn''t have very many try catches. Your idea of using auto pointers is a MUCH better idea, although I personally think that there is an inherit problem with exceptions if you must change the way you program to use it properly (ie, use autopointers when you would normally hardly ever use).
BTW, I don''t see the problem of cleanup. I have 1 try/catch in my winmain function. If an exception is thrown, my code execution is thrown back into winmain where it displays the error message, file, line number, etc, then calls the Shutdown function of my m_pClient variable (my base class). m_pClient then calls Shutdown on m_pGraphics, m_pGUI, m_pInput, m_pSound, etc. Everything gets deleted, returns back to winmain, and then the program exits.
- Houdini
- Houdini
ASSERT really does rock - why haven''t anyone told me about that before !!!!
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~I'm looking for work
ASSERT really does rock - oops twice
Edited by - JOL on October 4, 2000 12:15:28 PM
Edited by - JOL on October 4, 2000 12:15:28 PM
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~I'm looking for work
I really got a lot of ideas about error handling from this thread. But all you people are talking about is error handling for debugging. But what about effective error handling for the release build of the game. How should that be done?
In my opinion it should be informative to the user. Not just something like "And exception xxxxxxx occured in WinMain->Initialize->LoadBitmaps()" or "CreateDirectDrawEx() returned DDERR_GENERIC". But rather like "An error occured because of..blahblahblah...a possible solution could be...blahblah..."
How do you do it?
-René
In my opinion it should be informative to the user. Not just something like "And exception xxxxxxx occured in WinMain->Initialize->LoadBitmaps()" or "CreateDirectDrawEx() returned DDERR_GENERIC". But rather like "An error occured because of..blahblahblah...a possible solution could be...blahblah..."
How do you do it?
-René
Catching exceptions is the ideal way to do this in release mode. It''s actually not very useful to catch exceptions in the debugger, because you''ll go to where the exception is caught when the code breaks, not the point that threw it. So I have this in my code:
#ifndef _DEBUGtry{#endif //... //...some functions that throw exceptions#ifndef _DEBUGcatch (...){ //...}#endif
First off, personally, I rarely use try/throw/catch etc simply because I HATE not knowing EXACTLY what's going on im my program at any given time, and I've never learned precisely how they work.
I've given some thought to error handling in the past, and how I would get a list of function calls that showed the path through the program when the error occurred. Reading this thread some ideas have occurred to me.
Say you made a class (substitute funcs and static vars if you're so nuts you work only in c )
Many things could be added to make this class more self-supporting, but I presented it this way for simplicity.
Now I see it working like this: Allocate the class globally. Each function that you want to track an error path through would contain a constant string with it's name, or perhaps a short description of what it does, like 'Update view' for instance. When an error occurred within the function, it would set the FatalError bool to 'true', add it's const name to the list, then it would return. You would not necessarily return an error with the function because you might want to return a pointer or something more unusual that would be troublesome to check the value of. Now on returning, the function that called it would check FatalError. If 'true' it would then add it's own function name string to the list and also return. So it would go on down the list until you got to a point in your program (the root of the problem if you will) where you wanted to handle the error, display or log the whole path to a file, clean up and exit the program.
To handle the error, the class would contain a function to read the list in order, and concatenate the function name strings and inserting '->' between them. When you printed it out you have something like this:
FATAL ERROR 'theerror' occurred in:
Render()->somefunction()->someotherfunction()->yetanotherfunction()
I think this would work rather well, and wouldn't in any way slow down my program's operation. The only extra code would execute only if the program was being terminated anyway. I would wrap the whole thing up in member functions so that it was clean and pretty much took care of itself.
Obviously I haven't tested it, anyone have any comments/criticisms? Easier way? Speed/memory considerations? Additions/corrections?
I hope this is helpful, and hope it works. I want to use it myself
-Rath
Edited by - ratheous on October 4, 2000 6:16:48 PM
... Just can't get those source tags to work right. ohwell.
Edited by - Ratheous on October 4, 2000 9:50:12 PM
I've given some thought to error handling in the past, and how I would get a list of function calls that showed the path through the program when the error occurred. Reading this thread some ideas have occurred to me.
Say you made a class (substitute funcs and static vars if you're so nuts you work only in c )
class ErrorHandler{ bool FatalError;/*This would be checked everytime there was a chance of a failure.*/ DWORD ERRORCODE;/*If there was an error, this would contain a number referencing a lookup table of error strings.*/ LinkedList FunctionPath<char[30]>;/*Linked list template with links containing strings. The linked list could be implemented in any way you saw fit, CStrings or your personal string manager class could be substitued for the char array, this is simply for example. You could even do without a linkedlist and use a fifo or circular buffer, but that would be limited and likely more involved.*/}
Many things could be added to make this class more self-supporting, but I presented it this way for simplicity.
Now I see it working like this: Allocate the class globally. Each function that you want to track an error path through would contain a constant string with it's name, or perhaps a short description of what it does, like 'Update view' for instance. When an error occurred within the function, it would set the FatalError bool to 'true', add it's const name to the list, then it would return. You would not necessarily return an error with the function because you might want to return a pointer or something more unusual that would be troublesome to check the value of. Now on returning, the function that called it would check FatalError. If 'true' it would then add it's own function name string to the list and also return. So it would go on down the list until you got to a point in your program (the root of the problem if you will) where you wanted to handle the error, display or log the whole path to a file, clean up and exit the program.
To handle the error, the class would contain a function to read the list in order, and concatenate the function name strings and inserting '->' between them. When you printed it out you have something like this:
FATAL ERROR 'theerror' occurred in:
Render()->somefunction()->someotherfunction()->yetanotherfunction()
I think this would work rather well, and wouldn't in any way slow down my program's operation. The only extra code would execute only if the program was being terminated anyway. I would wrap the whole thing up in member functions so that it was clean and pretty much took care of itself.
Obviously I haven't tested it, anyone have any comments/criticisms? Easier way? Speed/memory considerations? Additions/corrections?
I hope this is helpful, and hope it works. I want to use it myself
-Rath
____________________________________________________
"Two wrongs do not make a right; it usually takes 3 or more."
Edited by - ratheous on October 4, 2000 6:16:48 PM
... Just can't get those source tags to work right. ohwell.
Edited by - Ratheous on October 4, 2000 9:50:12 PM
____________________________________________________
"Two wrongs do not make a right; it usually takes 3 or more."
Some mistakes are too much fun to only make once.
Never anger a dragon, for you are crunchy and you go well with brie.
Well, this is probably a crappy idea, but I thought id mention it anyway. Couldnt you use function pointers? In your class you could have a pointer to an errorhandler (this could be global if you like) and you can redirect it to anything, so when you run a function, it redirects it to a function that acts as an errorhandler for that function or something.
I actually justuse my own version of HRESULT. I wrap all of the DirectX error messages into text string, then just go if ( Hr.failed() ) Hr.ReportError(); and it does all the work for me.
I actually justuse my own version of HRESULT. I wrap all of the DirectX error messages into text string, then just go if ( Hr.failed() ) Hr.ReportError(); and it does all the work for me.
Err, the simples way to know where the error occured is todo something like
try{
buncha stuff;
}catch(thinghies){};
etc..
And have your classes, cuz you''r useing those to encapsulate things yes? throwing error of the type <thaClass>Error
for example a class names CStack throws CStackError:s and then you can use those classes to identyfi the error, could let them just be ints or sumthing and check for an error code, or you could supply both error code and string, go crazy!! just be sure to handle them someway, don''t want the app/game crashing randomly, thats what we are trying to avoid the whole time.
try{
buncha stuff;
}catch(thinghies){};
etc..
And have your classes, cuz you''r useing those to encapsulate things yes? throwing error of the type <thaClass>Error
for example a class names CStack throws CStackError:s and then you can use those classes to identyfi the error, could let them just be ints or sumthing and check for an error code, or you could supply both error code and string, go crazy!! just be sure to handle them someway, don''t want the app/game crashing randomly, thats what we are trying to avoid the whole time.
HardDrop - hard link shell extension."Tread softly because you tread on my dreams" - Yeats
October 05, 2000 01:18 AM
quote: Original post by Houdini
IMO that''s a bad way of handling exception handling. You are going to be littering your code with try catches and duplicating cleanup code. A proper exception architecture shouldn''t have very many try catches. Your idea of using auto pointers is a MUCH better idea, although I personally think that there is an inherit problem with exceptions if you must change the way you program to use it properly (ie, use autopointers when you would normally hardly ever use).
you don''t have to use auto pointers to use exceptions - but if you have two tools to aid in developing robust software, there''s no reason to only use one, is there?
and a ''proper'' architecture should have the right error handling in the right place it takes time to learn good ways to handle errors to keep a program clear, readable, and robust.
Alternatively, you can check every return value, and do some cleanup.
try { ... a whole bunch of stuff ... first_op(); second_op();}catch(...) { ... it didn''t work, so clean stuff up ...}
as opposed to:
if( !first_op() ) {...some cleanup... return ERROR_1;}if( !second_op() ) {...some cleanup...return ERROR_2;}
Exceptions give you more control over your code, and let you separate error handling code from code to perform actions when there are no errors.
Some functions will have a single try/catch block, others will have a few such blocks - it depends on the work being done, and what handling can/should be done. sometimes several functions will have no catch blocks, because errors can be passed up to a single function rather than handled in several places.
(I''m talking generally here - when I say ''you'', I mean "people in general")
Yes, it''s a new thing that you have to learn to use. But the same can be said of absolutely every technique you use now - once, you had to learn it, use it for a while, and get used to it. Then it started to seem natural.
quote:
BTW, I don''t see the problem of cleanup. I have 1 try/catch in my winmain function. If an exception is thrown, my code execution is thrown back into winmain where it displays the error message, file, line number, etc, then calls the Shutdown function of my m_pClient variable (my base class). m_pClient then calls Shutdown on m_pGraphics, m_pGUI, m_pInput, m_pSound, etc. Everything gets deleted, returns back to winmain, and then the program exits.
A good way to make users _hate_ you.
if you catch a truely evil exception (I''m really not even sure anything that bad would leave your computer functioning), and give a useful message, fine, but for most errors just making the program exit is utterly unacceptable.
seriously, if you just want to kill the program, have an asert() and be done with it. but just killing the program is not useful in many situations.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement