Sign in to follow this  
peter_b

How to make good use of exceptions?

Recommended Posts

Hello. Im trying to make more use of exceptions rather then return codes in my programs. I know how they work and all. What im not so sure about is how to make good use of them. When to use them. How to design your exception classes. When to catch exceptions and when to just re throw them. In short general good practice in using exceptions. Anyone know a good resource for that? Thanks in advance.

Share this post


Link to post
Share on other sites
A word of wisdom:

"Don't try hard to use exceptions. Using return values is enough 99% of the time. Exceptions should be used only in exceptional circumstances." - Me.

My guess is that exception handling is something that you have just discovered?

ace

Share this post


Link to post
Share on other sites
When i first learned of Exceptions i felt that they were really awesome, and can completely solve all of the worlds problems (maybe taking it a bit far, but at least solve some of my own code problems :))

As its all worked out, i dont often use exceptions. They definitely have their place and are certaintly an effective tool when used correctly - but im just more comfortable using error codes the majority of the time.

Anyway, to try and answer your questions - Exceptions should only really be used to indicate an exceptional circumstance. In the sense that, if something could potentially go wrong that you as the programmer have little control over (running out of memory, missing files) then you might want to throw an exception. Where to catch it depends on your overall code structure, but often its the calling code that would catch it immediately rather than re-throw.

Dont feel like having discovered exceptions you must start using them in your code immediately. My current project is around 5,000 lines of code so far and im not sure iv even used any exceptions at all.

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
A word of wisdom:

"Don't try hard to use exceptions. Using return values is enough 99% of the time. Exceptions should be used only in exceptional circumstances." - Me.

My guess is that exception handling is something that you have just discovered?

ace


Seconded. Never use exceptions for something you expect to happen often, you might use an exception if a resource is missing. You might throw an exception if the GPU don't support shaders, but your game needs 1.1 shaders. You should not throw an exception because the user tried to buy a weapon (s)he couldn't afford because that ain't "exceptional".

Share this post


Link to post
Share on other sites
A couple of good articles about exceptions:

http://www.freshsources.com/Except1/ALLISON.HTM
http://www.freshsources.com/Except2/ALLISON.HTM

The first introduces what exceptions are (probably not so relevant to you), and the last one talks more about how and when exceptions should be used.

Share this post


Link to post
Share on other sites
>you might use an exception if a resource is missing
Even in this case I wouldn't throw an exception, but rather
fallback to a 'dummy' resource - for textures you could use
a big red cross.

/R

Share this post


Link to post
Share on other sites
Use exceptions in exceptional circumstances :-p.

Personally, I rely heavily on exceptions for handling errors. If I buy() an item without the appropriate amount of gold, I would throw an exception. When it's a preformance issue, one can have parallel functions - "attempt_buy" which returns true/false, or "do_i_have_the_money_to_buy" in conjunction.

Boost smart pointer's lib is a good example of this (parallel methods for dealing with such a situation). There are 3 ways that spring to mind of generating a shared pointer for use from a weak pointer, for example:

boost::weak_ptr< T > weak( ... );

//Method 1: Try-or-throw
boost::shared_ptr< T > shared1( weak ); //throws bad_weak_ptr on failure

//Method 2: Try-then-verify
boost::shared_ptr< T > shared2( weak.lock() ); //shared2.get() == 0 on failure
if ( shared2 ) {
//..use shared2..
}

//Method 3: Verify-then-try (dosn't abstract well to multithreaded situations)
if ( ! weak.expired() ) {
boost::shared_ptr< T > shared( weak ); //could still throw if weak expired between the if statement and this line (e.g. program is multithreaded)
}



I use exceptions by default because they tend to be the easiest to use. If profiling reveals a problem, providing a more verbose version which rather obviously needs to have it's return checked (check_my_return_for_errors_or_i_will_punch_you( "he's serious" ), for example)

Share this post


Link to post
Share on other sites
Quote:
Original post by Kitt3n
Even in this case I wouldn't throw an exception, but rather
fallback to a 'dummy' resource - for textures you could use
a big red cross.
/R


You would fallback to a 'dummy' resource, does that mean that you won't indicate what you have done in any way. If suddenly the player is one big red-cross he sure wonders what have gone wrong with an exception you can easily catch it, give a message box "this resource is missing, continue with a dummy resource? <Yes> <No>" because there is going to be a message box and we will have to wait for the user anyway performance isn't a problem. If you just put a dummy resource the user have no idea that replacing the player model's texture with a new image in another format didn't work. You could of course check a boolean flag, like FailedToLoadResource or something, but you would have to do this on every resource even though there is less than 1 % chance that the error happens.

So in what case would you use an exception.

Share this post


Link to post
Share on other sites
Just to echo what was said by everyone else - do not use exceptions to catch an error made on the programmer's behalf.

For instance, if a function was expecting a positive integer, and you passed it a negative one, that is not an exceptional circumstance.

Programming languages such as Java promote the use of exceptions everywhere, but only because it has a decent garbage collector. In C++, it's important for your code to not depend on the use of exceptions, mainly for clarity and maintenance reasons.

Exceptions aren't evil, but just be careful. Clarity over convenience (some might disagree).

Share this post


Link to post
Share on other sites
Quote:
Original post by Wavarian
Just to echo what was said by everyone else - do not use exceptions to catch an error made on the programmer's behalf.

For instance, if a function was expecting a positive integer, and you passed it a negative one, that is not an exceptional circumstance.

Programming languages such as Java promote the use of exceptions everywhere, but only because it has a decent garbage collector. In C++, it's important for your code to not depend on the use of exceptions, mainly for clarity and maintenance reasons.

Exceptions aren't evil, but just be careful. Clarity over convenience (some might disagree).

Why not to use an exception in that case?
What is so clear about allowing a bug to happen?
If you use an exception to catch this bug, then you can immediatly correct it.
I am sure a player would be happy to discover his character has negative intelligence or something like this.
Exception should be used to catch things you didnt intend that will happen.
You can quote this line.

If something happens in my program that I didnt intend it to happen, such as a red pixel in the bottom left part of the screen, I want to know about it. Even if the program would work with this bug.

Share this post


Link to post
Share on other sites
Quote:
Original post by The C modest god
Quote:
Original post by Wavarian
Just to echo what was said by everyone else - do not use exceptions to catch an error made on the programmer's behalf.
....

Why not to use an exception in that case?

Programmer error is a bad place to use exceptions because you need to handle exceptions somehow. It's better to use assertions to catch programmer error, with the exception of programmer error coming out of scripts, which generally then raises an exception in the scripting system, not a C++ exception.

Share this post


Link to post
Share on other sites
Quote:
Original post by Kitt3n
Even in this case I wouldn't throw an exception, but rather
fallback to a 'dummy' resource - for textures you could use
a big red cross.

/R


Well, I would fall back using an exception. [wink]

Throw an exception if the resource is missing, and then in the catch block, you insert the dummy resource instead. (And probably output an error message to a log file or something)

That way, you get to smoothly recover from errors, without having to surround everything with error code checking.

Share this post


Link to post
Share on other sites
Quote:
Original post by The C modest god
Why not to use an exception in that case?
What is so clear about allowing a bug to happen?
If you use an exception to catch this bug, then you can immediatly correct it.
I am sure a player would be happy to discover his character has negative intelligence or something like this.
Exception should be used to catch things you didnt intend that will happen.
You can quote this line.

If something happens in my program that I didnt intend it to happen, such as a red pixel in the bottom left part of the screen, I want to know about it. Even if the program would work with this bug.


An exceptional circumstance is one which you are unable to do anything about. If you have a bug in your code that allows a character to have a negative intelligence value then that's up to you to fix. If a required data file is missing, you can't do anything about that, it's out of your hands - so this would be a good reason to use an exception. Same goes for when CreateWindowEx() fails.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Quote:
Original post by The C modest god
Quote:
Original post by Wavarian
Just to echo what was said by everyone else - do not use exceptions to catch an error made on the programmer's behalf.
....

Why not to use an exception in that case?

Programmer error is a bad place to use exceptions because you need to handle exceptions somehow. It's better to use assertions to catch programmer error.

In most environments (not C++), though, assertions just throw exceptions anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by Arild Fines
Quote:
Original post by SiCrane
Quote:
Original post by The C modest god
Quote:
Original post by Wavarian
Just to echo what was said by everyone else - do not use exceptions to catch an error made on the programmer's behalf.
....

Why not to use an exception in that case?

Programmer error is a bad place to use exceptions because you need to handle exceptions somehow. It's better to use assertions to catch programmer error.

In most environments (not C++), though, assertions just throw exceptions anyway.


Perhaps, but labelling your assertions as assertions makes it easier to conditionally-compile them out, etc. Always prefer more specific/expressive constructs over general-purpose ones when possible (the same reason you use for instead of while where appropriate, or while instead of manually looping with a goto in a conditional).

Share this post


Link to post
Share on other sites
Quote:
Original post by Wavarian
Quote:
Original post by The C modest god
Why not to use an exception in that case?
What is so clear about allowing a bug to happen?
If you use an exception to catch this bug, then you can immediatly correct it.
I am sure a player would be happy to discover his character has negative intelligence or something like this.
Exception should be used to catch things you didnt intend that will happen.
You can quote this line.

If something happens in my program that I didnt intend it to happen, such as a red pixel in the bottom left part of the screen, I want to know about it. Even if the program would work with this bug.


An exceptional circumstance is one which you are unable to do anything about. If you have a bug in your code that allows a character to have a negative intelligence value then that's up to you to fix. If a required data file is missing, you can't do anything about that, it's out of your hands - so this would be a good reason to use an exception. Same goes for when CreateWindowEx() fails.

Of course it is up to me to fix, but how can I fix it if I don't know when it happens because I didnt use an exception?
If something happens in your program that you didnt intend it to happen, even if now it is harmless, later it might cause a bug which you wont have any hell of idea why it happens.


Share this post


Link to post
Share on other sites
Quote:
Original post by The C modest god

Of course it is up to me to fix, but how can I fix it if I don't know when it happens because I didnt use an exception?


Then use an assertion instead.

Share this post


Link to post
Share on other sites
But the case above of a negative integer being passed where a positive integer is required is not neccessarily suitable for an assertation, as it is an invariant, and may need to be enforced even in release code.
So an exception could be more suitable in this case (think std::vector.at()).

Share this post


Link to post
Share on other sites
Quote:
Original post by Wavarian
SiCrane is right.

Do not mistake exceptions for use as a debugging tool, that's not their purpose.


This said, your debugger should be smart enough to break when an exception is thrown. If it's not, upgrade. If you're using GDB:

(gdb) catch throw                      # break on any exception being thrown
(gdb) catch throw my_exception_type # break on a my_exception_type being thrown
(gdb) catch catch # break on any exception being caught
(gdb) catch catch my_exception_type # take a guess


GDB's catch can also break on everything from signals to DLL (un)loading to thread forks. Read (gdb) help catch for more information on that.

Share this post


Link to post
Share on other sites
Exceptions scare a lot of game developers because they hear horror stories of how slow they can be. In all honesty they really aren't that slow at all. If anything the stack unwinding is slow when an exception is thrown, but the whole point is to get things working so no exception is ever thrown.

That said, I use exceptions everywhere. I *NEVER* use return error value. This is because WAY too often error returns are ignored and that causes loss of time (debugging), money (paying the debuggers), moral (who wants to hunt bugs?), etc.

There are proposed ideas of error values that must be read or the program will crash. That's a good idea, but hasn't been solidly implemented and tested in the real world. Even the most promissing versions right now still have major flaws.

So...when do I use exceptions? In exceptional cases. That's what everyone says...let me clerify more: I make the normal case painfully obvious like ReadFile( File & ). If for any reason at all that file cannot be read, it is an exception.

EDIT: Typo

Share this post


Link to post
Share on other sites
Quote:
Original post by The C modest god
Quote:
Original post by SiCrane
Quote:
Original post by The C modest god

Of course it is up to me to fix, but how can I fix it if I don't know when it happens because I didnt use an exception?


Then use an assertion instead.

What is an assertion?

Ok, I have read about assert in bjarne's book.
First, it is some sort of C backward compatability thing?
It doesn't work well in templates.
It gives the line in which it was called, but that is useless if you encapsulate it, which you propabbly would.
It just calls a function? it would not call all the destructors?
So it is not suitable to deal a bug which happened in the end user's computer, because then you need to call destructors, do some stuff and then properly end your program.
So I don't see why not to use exceptions to catch logical bugs (which usually develope later to a much horrific bugs) on the end user's computer.
So what if it is called exception? and you can derive from it the word exceptional?




Share this post


Link to post
Share on other sites
Geeze I have a bad habbit of not justifying my answer. Okay...

ReadFile( ); is incredibly easy to understand. It is self-documenting. If anyone doesn't know what ReadFile( ) does they should be fired. This is a good thing.

And if an exception is thrown, you already know part of the "Why did I get an error?". Because the file cannot be read. So all you need now is "Well why can't the file be read?". That's there the exception comes in.

try
{
ReadFile( );
}
catch( DoesNotExist & e )
{
// couldn't read file because the file does not exist
}
catch( InsufficientPermission & e )
{
// couldn't read file because there was insufficient permission
}

You will notice that those exceptions are also very self-documenting. I added simple comments just to prove the point. After you read the exception type, you knew exactly what went wrong. If you then read the comments you would go "Geeze what a waste of time." That's how self-documenting they are.

They are so easy to understand that you probably dislike the comments. It would be better to not have provided the comments!

And we all know programmers don't like to write comments anyway. So we are hitting two birds with one stone.

Sure you can write enums with error values that are this descriptive also. But the minute any of those possible errors is ignored, you have no idea what could be wrong. No simple self-documentation, no stack trace to the error. Nothin'.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this