tags:

views:

139

answers:

6

Hi, What is better coding practice: if I have to have a try/catch block shall I place everything (every initialization and so on) in this block or just those variables which may throw? Is there any difference between those two constructions?

In example:
Having:

struct A  {
    A();
    int a;
    int* b;
};    

and later on in .cpp:

A::A() {
    a = 5;
    try {
       b = new int;
    }
    catch(...){ 
    }
}

or

A:A()  {
   try {
     a = 5; //this time in try block
      b = new int;
   }
   catch(...) { 
   }
}

is there any difference between those two constructs or is this in a way if I have to have a try/catch block I may aswell put everything in it? Thank you.

P.S. For God efin sake, formatting here drives me really crazy! And I know that I mentioned this many times, I'm not going mad.

+9  A: 

I think a good general principle is to make a try block as "narrow" as possible -- don't put in it things that you believe won't ever cause exceptions. That way, should you ever be wrong and have one of those "can't cause exception" parts actually do cause an exception, you won't be accidentally "swallowing" the astonishing exception (and no doubt dealing with it in inappropriate ways, since your code would not be expecting that exception but other kinds).

Alex Martelli
+1. In addition, the try statement creates a new SAR (Scope Activation Record) on the stack. Read more about activation records here: http://webster.cs.ucr.edu/AoA/Windows/HTML/IntermediateProceduresa2.html.A scope activation record is like an Activation Record but only pushes on the stack the local values within the try parenthesis, and contains a pointer to the AR (Activation Record) that opened it. In poor words there could be different scopes using different compilers when using your different approaches. Putting everything in a try block does also slows down performance a little.
bodom_lx
+3  A: 

In your code, I would not use a try block at the point you indicate at all. Memory allocation errors are actually both very rare and very difficult to recover from. I would probably catch the exception in main, log the error and exit the program.

More broadly, in C++ you should not wrap every function that could throw in a try block. You should instead write code that can cope with exceptions, using well-known C++ idioms like RAII.

anon
I think he's using that example to represent all situations in which you could choose to wrap a whole method in a try/catch block or just trap a few lines of code that could be responsible to throw an exception. In any case, the second approach is right :)
bodom_lx
+2  A: 

In addition to the very good points by Alex and Neil, the narrow try block makes for an easier to understand code. A future maintainer will know more easily what's going on.

Gorpik
+1 A very good point, wrapping up something else would indicate that you expect every line of code to throw some kind of exception.
daramarak
+1  A: 

@ Alex, I disagree. You should group logical parts of your program into try catches that should fail or pass as a whole. If something fails, even if you didn't expect it your code should be exception safe and the whole operation should fail and all resources should automatically be released. If you make them narrow then you just end up with tons and tons of try's and catches. Why not just use IF's? (but wasn't that the point of exceptions in the first place? avoid tons of ifs?)
Parashift agrees with me too.
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.12
read 17.12 and 17.13.

Chris H
This is more regarding programming style and point of views. There are people that prefer to precisely define "dangerous" code blocks and there are other people that prefer to surround the code seen as logic parts, as you point out. The first approach is very precise but verbose and performant (also gives precise alerts and focuses). The second approach is elegant and make code blocks look and act more like transactions in database. The decision does also depend on the type of program you are writing. For beginners, I would recommend the approach suggested by Alex
bodom_lx
A: 

In my code, I rarely ever catch anything, except in main(). If you feel like you need catch blocks to clean up after yourself, you do something wrong and need to have a good look at the RAII idiom. As for anything else - an exception should be thrown under exceptional circumstances only, and it's very hard to come up with something generic and smart to do in exceptional moments.

sbi
A: 

Another way to look at this is to include statements in a try block when they all need to succeed or fail together. This way, catch blocks act as a kind of transactional feature in your code. So, you can do something like:

// save current state
try {
  // a few statements
  // that each modify the state
} catch (e) {
  // rollback to original state
}

In your example, assigning to member variable a changes the state of the object, so it should be inside the try block.

Mark Bessey