Exceptions and performance

Started by
30 comments, last by MaulingMonkey 19 years, 4 months ago
I'm not having a problem, I'm just curious as to how exception handling in C++ works and what it means in terms of performance. What exactly do the try and catch tags do to the program? Obviously you wouldn't plan on your code throwing an exception during normal operation, so would putting these try and catch statements in your code be better for performance than say, checking for null pointers every time? I'm really not clear on how the whole thing works... Any links/comments?
Advertisement
Well, if you're using exceptions outside your "must-be-fast" rendering code (or sth like that) then I think that exceptions won't slow you program. They aren't very slow, but on the other hand they won't be very fast eaither, probably slower than what you can write yourself (hovewer, there are many situations when use of exceptions will save you from writing ugly program that uses [exorcism] goto's [/exorcism]

Quote:What exactly do the try and catch tags do to the program?


I'm not sure (it's just a hypothesis that surely is wrong) but they actually may do _nothing_ to the program, they may just exist to tell programmer "here I am! be aware of me!" etc. or to point out compiler where exception code starts. But probably I'm totally wrong and I would love to hear somebody who knows exactly what's going under the hood.

Quote:Obviously you wouldn't plan on your code throwing an exception during normal operation, so would putting these try and catch statements in your code be better for performance than say, checking for null pointers every time?


Sure, exceptions can be used when non-critical thing occurs, but in my opinion using them to check if memory was properly allocated is... well, better to say that I prefer to check for null instead :-)
Exceptions are generally used in the layer of software that inerfaces with hardware. People can suddenly unplug a cable when your program is trying to access the digital camera over the firewire or a network cable is unplugged, etc.

People tell you not to use them because of performance because they don't want you to write code like

try
{
while(1)
{
(p++)->blah();
}
}catch(...){/*loop done!*/}

That is indeed slower than a normal loop. Someone else can go into more detail of the assembly code generated for exceptions if they feel like it since you did ask. You seem to have the right idea, though.
Don't use try...catch in tight loops. As long as you just use it around the outside of your loops it shouldn't even be a noticible difference.
Execeptions are typically used to check for critical errors within a program. Namely, these are the type that would normally result in you closing down the program or it crashing. So in theory, NULL pointer checks can be done that way, so long as all memory is allocated with new and you're catching the exception thrown when new fails (there is one, right?). Otherwise, you still have to have checks in your code that will throw the exception when things go awry.

That said, here's a synopsis of how exceptions work. When you set up a try/catch block, the code address for the catch part is saved somewhere (not too sure where). Then the code in the try block is executed. If during that execution, something throws an exception, I believe a check is done to determine if there is anywhere in the call stack that has an exception handler implemented for the specific type of the exception thrown. If there is, the program immediately unwinds the stack up to the appropriate exception handler and executes the code in the catch block. Once the stack is unwound, you cannot go directly back to where you were. Execution continues from just after the catch block. Unwinding always occurs to the most deeply nested handler appropriate for the thrown object. Note that dynamic memory is not deallocated when an exception is thrown unless you explicitly do so. This means that you may have to implement handlers at multiple levels whose only purpose is to clean up then throw the exception up to the next level of the call stack.

Exceptions shouldn't be performance eaters if you use them properly. Most of the overhead comes only when an exception is handled because the call stack has to be unwound to the right point. And if you're using them only in cases where the program would have to terminate anyway, you might lose a few cycles as your program terminates. In my opinion, this is better than it crashing or leaking memory (though memory is usually cleaned up by the OS for you at termination).

There are other useful ways to use exception handlers that aren't for critical errors, but the nuances of when to use them are subtle and it's difficult to describe when it should or shouldn't be done. Used as a code flow controller, exceptions can - on the rare occasion - prove to be an extremely elegant solution, but for the most part, you'll end up with hideous spaghetti code.

-Auron
"Exceptions are generally used in the layer of software that inerfaces with hardware. "

I agree that this is one use of them but that's hardly the only or the main or even the most important use of them although I don't think you meant that the hardware software interface is their most common use:)

They are used when you can't always return an error code, IMHO this is most useful when calling a constructor since you can't return an error code.

They can also be used for times when you can't handle an error or maybe more correctly you shouldn't handle an error in a particular location.

An out of memory error or null pointer exception are two good cases. You can't always decide whtat to do at times like that so you let teh exception propogate back up your app to an area where you can handle it.

And don't worry about the speed hit of exceptions, like the others mentioned it more than likely won't hurt your app. Alot of game logic is now written in scripting languages:)


Cheers
Chris

CheersChris
Standard C++ exceptions roughly correspond to the Standard C setjmp and longjmp functions. Each try has an entry and exit cost (e.g. setjmp to both enter and leave) and when an exception occurs a bunch of stuff happens but that generally doesn't matter because something has gone horribly wrong anyway.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
I couldn't care less about the performance of exceptions when an exception is thrown. As that's supposed to be... well.. an exceptional case :)

What i'm interested in, though, is knowing what performance impact exceptions have on the "normal" code, ie. the code executed 99.999% of the time.

For example, if i do a single try/catch in my "main" function, is the performance of all the program's sub functions affected or not? Especially if some functions are called millions of times.

I'd also like to know if a function, that is called a lot, throws an exception (ex.: an inlined function in a maths class, checking for an argument validity), how much is performance affected?

Y.
My guess is that the overhead is slim to none. If I'm right on this, there should only be some extra stuff don when a try/catch block is created and depending on how it's done (which is the part I don't know), odds are that the address of the handler is stored globally. It shouldn't be getting passed as an invisible parameter to every function called within the try block.

As for throwing exceptions, I don't see it as being a performance issue except for when the exception is actually thrown. As I explained, it will unwind the stack to the scope of the handler. If you aren't throwing the exception, it should never give overhead. If you're using it as a check for passing a negative number to the sqrt() function where you recover afterwards, then I imagine it would create overhead.

But if you are using them like that, then don't. It's not what they're for. Just having a function that is capable of throwing an exception should not create overhead in using that function for the non-exceptional cases.

-Auron
Well the use I had in mind was in a client/server app where you can't always trust the data. As an example... when one player requests to give gold to another player the client program sends a packet translating to "I want to give X gold to player S" where S is a number that identifies the player. Since I use this number S as an array index, it's POSSIBLE that it might not be a valid client (null pointer errors, index out of bounds errors... crash). Would it be faster to just check for these problems directly, or would a try/catch statement not affect anything as long as an exception does not occur (rare). I'm not as concerned about a few extra cycles being lost when an exception DOES occur, because like somebody has already stated, things have already went wrong anyways.


Edit: Exactly what I'm most interested in Ysaneya... leave it to somebody else to better state my own question.

This topic is closed to new replies.

Advertisement