Exception Handling

Started by
8 comments, last by Kylotan 24 years ago
I just wondered if anyone had any well-structured ways of dealing with throwing and catching exceptions? I often end up catching them nearer the source, if only to make it easier to tell what the precise problem is, but then I end up writing so many catch blocks for critical errors that I may as well just use exit() anyway. I''ve thought about generating a more descriptive exception type and throwing it almost all the way down to main() (eg. to MainGameLoop() or something) but I''m still not sure whether this would be best. Any opinions?
Advertisement
Well, I have try block in the main and that is where my game objects get created. I throw objects which are cought in one try block at one place. Then I do something like this in the catch block...

try
{
// exception thrown somewhere within a method of an object
if(FAILED(hr))
throw CDDrawException(hr, __FILE__, __LINE__);
}
catch(CDDrawException& e)
{
e.WriteToFile();
}
catch(...)
{
// Signal a generic error
CWindowsError generic_error(FALSE, "General exception was raised...", __FILE__, __LINE__);
generic_error.WriteToFile();
}

All the DDraw error codes are in my CDDrawException object,
all dsound and dinput are in their own exception objects. I haven''t progressed enough to see if this will work in a large program but so far it''s working ok.

Jerry
Can you give an example of how exceptions complicate your code? If you structure it correctly, using utility classes to properly allocate/release resources and structuring code so that at every step the system is in a stable state, regardless of exceptions, then you should have code relatively free of complicated try/catch nesting. Take a look here at the appendices to The C++ Programming Language (3rd Edition) for how to effectively structure exception safe code.

MSN
Thanks for the link, but I''m not concerned with exception safety. My objects and memory allocation state is fine. I''m concerned with deciding where to put exception handling, which functions should throw things and which are better off just returning values, what should be thrown, where should they be caught, etc etc. I would like some examples of how other people are using exceptions to simplify the error-checking process, rather than using it as a way to ensure objects are deallocated properly (which is a notable goal, just not what concerns me here).
Hmm, reading that post about the DDraw errors had me smacking myself in the head for constantly writing a three mile function to parse errors.

I''m going to start using exceptions from now on, they are definately "a good thing".


#pragma DWIM // Do What I Mean!
~ Mad Keith ~
**I use Software Mode**
It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
The best thing I came up with exception handling is error tracing.
Note, in the case of
A() calls B() calls C();
D() calls B() calls C();

If C generates an error/exception, you get to debug two different functions, A and D(How fun!)

However, properly structured exception handling can trace the call stack.
I will be brief here,

Create an exception object.
Add a stack/queue/list to the object as member variable.
Add also an error message string.

At the end of every function, catch 2 different exceptions, 1 is of your exception object type, and another is ...
If you caught an object of your exception object type, append the current function to the call stack(push_front), and throw it again.

At the end of all functions, simply print out the call stack information and error message.
quote:Original post by Kylotan

Thanks for the link, but I''m not concerned with exception safety. My objects and memory allocation state is fine. I''m concerned with deciding where to put exception handling, which functions should throw things and which are better off just returning values, what should be thrown, where should they be caught, etc etc. I would like some examples of how other people are using exceptions to simplify the error-checking process, rather than using it as a way to ensure objects are deallocated properly (which is a notable goal, just not what concerns me here).


Ah, in that case, put the try/catch/throw stuff in places where it''s most convenient, i.e. if a function is easier to understand w/o a try/catch clause, restructure it so it doesn''t need it. Also, determine what is exceptional (crashing) behavior, and what is an error (this is specific to each application), and place the throws accordingly.

I''d personally put throws wherever you have resource allocation that fails, or come up w/ a situation where the data you have leaves the system in an inconsistent state. W/o more contextual information, no one can really give a qualified answer.

MSN
I always, and only have the try/catch block in the main function. My style, anyway.

If you are afraid of not freeing naked memory pointers when exception occurs, then try to use
std::auto_ptr< class T >

e.g.:
std::auto_ptr < CScreen > pScreen(new CScreen);
...
pScreen-> SetMode(...); // threat it as normal ptr

If any exception/throw occur, or more generic (and easier), when pScreen is out of the scope, pScreen is automatically deleted.

...hmm....which to throw or not to throw... to me, a file error don't need exception. Here's something I consider exception:
1) Memory allocation error
2) DirectX error
3) Window creation error or important Win32 function error.

Generally, any error that make my program can't continue is considered an exception. So again, file error don't make my program stop.


Edited by - DerekSaw on 4/18/00 10:35:34 AM
"after many years of singularity, i'm still searching on the event horizon"
quote:Original post by DerekSaw
Generally, any error that make my program can''t continue is considered an exception.


Yes. However, the reverse is not true: exceptions do not always mean that the program can''t continue. E.g. Properly handling virtual memory, divide by zero, etc.

MSN
Exception is just like error handling. In case of errors, especially business applications, it isn''t a very graceful to abort the program when you can''t allocate that 2 bytes more of memory. Instead, they gives a warning to the user, or maybe save the temporary unused memory into disk, or whatever.
It offers a way to handle ''exceptional'' situations, and allows you to go a different way in handling a case if the previous solution fails.

This topic is closed to new replies.

Advertisement