How much should I try and catch?

Hi!
I was thinking about ways to design solid and error-prone programs, so I ended up wondering if "try" and "catch" are a good way to handle all exceptions.
Basically, I'm wondering how should an ideally "bug-free" program should be structured? Is it a good idea to create a global architecture that automatically performs the process of trying and catching for every routine? Or is there a way to handle exceptions in a cleaner, easier, and perhaps more CPU efficient manner?
Or, in other words, how much should try and catch ideally be used?
Thanks.
http://www.parashift.com/c++-faq/exceptions.html
http://yosefk.com/c++fqa/exceptions.html

Or, in other words, how much should try and catch ideally be used?

I can't give a general answer because the question itself isn't general: this depends entirely on your code and your intent.

What I can say is that you can put the try around the entire body of the function.
Perhaps this simplifies the layout a bit.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void function(int a, int b) try
{
    // ...

    // the body of the function

    // ...
}
catch (/* exception type 1 */)
{
    // ...
}
catch (/* exception type 2 */)
{
    // ...
}

Last edited on
try/catch should be at the level of code that can actually do something about the error.

A common mistake with exception newbies is that they treat exceptions like error codes and put damn near every line in its own try block, which defeats the entire point. The goal is to consolidate the error handling code in one place, so you don't have to be constantly checking to see if your last operation succeeded.

A simplistic example of a good way to use exceptions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// function called when the user presses a button to do something complex
void onButtonPressed()
{
    try
    {
        doComplexOperation();
    }
    catch(std::exception& e)
    {
        // report exception message to the user, tell them the operation failed
    }
}

void doComplexOperation()
{
    doStep1();   // any one of these functions may potentially throw an exception if they fail
    doStep2();
    doStep3();
    doStep4();
}



Note that doComplexOperation does not try/catch. This is important because handling the failure is not part of the operation itself (at least not in this case).

Conceptually, if any part of the operation failed (threw an exception), then the operation as a whole should fail (throw an exception).

In that same mindset... the error is handled in the onButtonPressed function because pressing the button didn't fail (therefore it shouldn't throw an exception)... only the operation it performed did.

This allows you to do other things:

1
2
3
4
5
6
7
8
9
void onAnotherButtonPressed()
{
    try
    {
        doComplexOperation();
        doYetAnotherComplexOperation();
    }
    catch(...){...}
}


If doComplexOperation did the try/catch itself... then flow would continue through to doYetAnotherComplexOperation, even though it shouldn't (since presumably, the 1st complex operation was a prerequisite to completing the 2nd).



The hard part to using exceptions properly is not with the try/catch blocks... but with writing exception-safe code. Exception-safe code has to be aware that an exception could be thrown at any time... and has to be mindful that when that happens, things can be left in a "half completed" state.

EDIT: ninja'd by Catfish.
Last edited on
Exceptions are simply how functions are required to exit when they fail to establish invariants/post-conditions (e. g. constructors that fail) and how wide-contract functions exit for certain unwelcome inputs (e. g. vector::at() ). They don't make your program any more or less "bug-free", except by making the code easier to read and reason about (assuming you don't try/catch every function call, which is the wrong thing to do).
A good general purpose introductory link is probably http://www.drdobbs.com/when-and-how-to-use-exceptions/184401836 if you don't have Coding Standards or Exceptional series.
@Disch Thank you. That was a great answer. I can see how exceptions are meant to handle the failure of individual actions (rather than instructions or big, global procedures) that - if terminated mid-way - should not cripple the execution of the wider system that they are part of.

They don't make your program any more or less "bug-free", except by making the code easier to read and reason about
Well, there's a higher chance of avoiding bugs if you're prepared for a bulldozer to fall in the middle of your function, right? :D

Many thanks to everyone for the articles!
Last edited on
Topic archived. No new replies allowed.