views:

286

answers:

3

I've managed to get through my C++ game programming career so far virtually never touching exceptions but recently I've been working on a project with the Ogre engine and I'm trying to learn properly. I've found a lot of good questions and answers here on the general usage of C++ exceptions but I'd like to get some outside opinions from here on whether Ogre's usage is good and how best to work with them.

To start with, quoting from Ogre's documentation of it's own Exception class:

OGRE never uses return values to indicate errors. Instead, if an error occurs, an exception is thrown, and this is the object that encapsulates the detail of the problem. The application using OGRE should always ensure that the exceptions are caught, so all OGRE engine functions should occur within a try{} catch(Ogre::Exception& e) {} block.

Really? Every single Ogre function could throw an exception and be wrapped in a try/catch block? At present this is handled in our usage of it by a try/catch in main that will show a message box with the exception description before exiting. This can be a bit awkward for debugging though as you don't get a stack trace, just the function that threw the error - more important is the function from our code that called the Ogre function. If it was an assert in Ogre code then it would go straight to the code in the debugger and I'd be able to find out what's going on much easier - I don't know if I'm missing something that would allow me to debug exceptions already?

I'm starting to add a few more try/catch blocks in our code now, generally thinking about whether it matters if the Ogre function throws an exception. If it's something that will stop everything working then let the main try/catch handle it and exit the program. If it's not of great importance then catch it just after the function call and let the program continue. One recent example of this was building up a vector of the vertex/fragment program parameters for materials applied to an entity - if a material didn't have any parameters then it would throw an exception, which I caught and then ignored as it didn't need to add to my list of parameters. Does this seem like a reasonable way of dealing with things? Any specific advice for working with Ogre is much appreciated.

+15  A: 

You don't need to wrap every last call to Ogre in try { ... } catch. You do it wherever you can meaningfully deal with the exception. This may be at the individual call site in some cases, or it could be in a high-level loop of some sort. If you can't deal with it meaningfully anywhere, don't catch it at all; let the debugger take over.

In particular, you shouldn't catch exceptions in main() for precisely the reason you cite (at least, not during development; you should in production).

Marcelo Cantos
+1 for "Wherever you can meaningfully deal with the exception"
Yacoby
So would meaningfully dealing with the exception apply to my last example of finding parameters? As long as nothing has been modified before the exception then it's not going to cause any problems.timday pointed out how to debug the exceptions when they're thrown which will help a lot, if I take out the main try/catch in debug mode what will happen if exceptions aren't caught?
identitycrisisuk
When exceptions aren't caught the debugger catches it, and shows you the point where it was thrown from.
Christopher
@identitycrisisuk: Certainly, you're entitled to discard whatever exceptions you want, as long as it makes sense for the state of your application. Just remember that exceptions are expensive, so you don't want them happening at frame-rates. But if it's during configuration of rendering resources, it shouldn't matter too much. Uncaught exceptions are trapped by the debugger; it should be as if a breakpoint was set at the point the exception is thrown (full stack trace, inspect variables and stack frames, etc.).
Marcelo Cantos
@Marcelo Thanks, that about clears up all my questions. I'll be removing the main try/catch in debug mode but leave it there for release so it's like a crash catcher dialog. I think I was ok to handle that one exception as it happened but any in future I'll try to fix the source of it rather than let it happen at run time.
identitycrisisuk
+6  A: 

I don't know anything about Ogre, I'm afraid, but the general rule with exception handling is that you catch the exception as far as possible from the throw site, but no further. However, this is only possible if the code that throws the exception uses RAII to look after allocated resources. If the code uses dynamic allocation to plain pointers, or other forms of manual resource management, then you need try-blocks at the call site. If this is the case, I'd say use of exceptions is a bad idea.

anon
I think Ogre is mostly ok from a resource allocation point of view, most of it uses it's own shared pointer class (which they don't recommend you reuse though...) and you can leave it to clean up once you're not using stuff anymore.
identitycrisisuk
+4  A: 

You seem to be unaware of how to debug exceptions. Either

  • Bring up the VS Debug/Exceptions dialog and tick the C++ Exceptions box. This will give you an opportunity (a dialog appears) to debug when an exception is thrown.

or

  • If you've built Ogre source, set a breakpoint in the Ogre::Exception constructor and when it attempts to throw one you'll break with a call stack where the next level up is the throw site.
timday
Thanks a lot, I knew there'd be something but couldn't quite find it. Should have thought of the constructor breakpoint too.
identitycrisisuk