What to put in the try-block

E

Erik Wikström

I just thought of a question that I have never seen discussed before
(perhaps it is trivial?) and while I think I know the answer I realise
that others might have other oppinions, which is why I ask it here.

How much code should one put in the try-block, i.e. if you have code
such as this:

foo;
bar;
baz;
try {
somecode;
}
catch (exception& e) {
// ...
}

and you have to posibility to also put foo, bar, and baz in the try-
block, should you do so?

I think no, since by limiting the stuff in the try-block I more
clearly indicate what might throw (or which depends on something not
throwing) than I do if I put as much as possible in it. Are there any
other oppinions or motivations?
 
I

Ian Collins

Erik said:
I just thought of a question that I have never seen discussed before
(perhaps it is trivial?) and while I think I know the answer I realise
that others might have other oppinions, which is why I ask it here.

How much code should one put in the try-block, i.e. if you have code
such as this:

foo;
bar;
baz;
try {
somecode;
}
catch (exception& e) {
// ...
}

and you have to posibility to also put foo, bar, and baz in the try-
block, should you do so?

I think no, since by limiting the stuff in the try-block I more
clearly indicate what might throw (or which depends on something not
throwing) than I do if I put as much as possible in it. Are there any
other oppinions or motivations?
Well that all depends on whether you can recover form an exception in
foo and then continue to execute bar and baz. If not, you may as well
put the lot in the try block.
 
E

Erik Wikström

Well that all depends on whether you can recover form an exception in
foo and then continue to execute bar and baz.  If not, you may as well
put the lot in the try block.

In the example I assume that foo, bar, and baz can not throw, only
somecode can. So the question could be reformulated as: is there any
value in including more code than that which can throw, or that which
depends on successful execution of the code that can throw, in the try
block?
 
J

Joe Greer

I just thought of a question that I have never seen discussed before
(perhaps it is trivial?) and while I think I know the answer I realise
that others might have other oppinions, which is why I ask it here.

How much code should one put in the try-block, i.e. if you have code
such as this:

foo;
bar;
baz;
try {
somecode;
}
catch (exception& e) {
// ...
}

and you have to posibility to also put foo, bar, and baz in the try-
block, should you do so?

I think no, since by limiting the stuff in the try-block I more
clearly indicate what might throw (or which depends on something not
throwing) than I do if I put as much as possible in it. Are there any
other oppinions or motivations?


There are, of course, several of issues to consider. Since anything
declared in the try block is unavailable in the catch block, you
automatically end up with stuff that is at least declared outside the
try/catch construct. I mean, if nothing else, you often want to log
something in the catch block. However, balancing that is the desire to
keep things that logically belong together in the same scope so that it
is obvious that they belong together. So, I guess the points I have
made so far are that you likely to have things outside the try block
anyway, therefore aesthetics doesn't really play into the picture. On
the other hand, code grouping might.

From a practical point of view, the point of a try catch is a form of
flow of control so that you can automatically skip some code if a
predecessor throws. In that case, you will want the code to be skipped
in your try block. In your example, if bar can throw and baz relies on
the results of bar, then you will definitely want both bar and baz in
the try block. This plays more into my own personal view which is that
try/catch is a flow of control statement (though somewhat of a
syntactical heavyweight) and much like an if stmt, you only put the code
in the try block which is useful to be there. Now, I will also say that
I find the try/catch syntax heavy weight enough that I try to have at
most one in a function. This, for me, addresses the code grouping point
above.

Just my opinion.
joe
 
J

James Kanze

I just thought of a question that I have never seen discussed before
(perhaps it is trivial?) and while I think I know the answer I realise
that others might have other oppinions, which is why I ask it here.
How much code should one put in the try-block, i.e. if you have code
such as this:
foo;
bar;
baz;
try {
somecode;
}
catch (exception& e) {
// ...
}
and you have to posibility to also put foo, bar, and baz in the try-
block, should you do so?
I think no, since by limiting the stuff in the try-block I
more clearly indicate what might throw (or which depends on
something not throwing) than I do if I put as much as possible
in it. Are there any other oppinions or motivations?

Two guiding principles, IMNO:

-- I like to keep the try blocks as small as possible, in order
to keep the error handling code as near to the source of the
error as possible.

-- If a variable will not meet the required invariants in the
catch clause, or after, its definition belongs in the try
block.

In general, however, it's best to avoid try blocks completely,
and use destructors. Even to the point of defining a special
transaction type to handle it. And while I've not experimented
with it, I suspect that something along the lines of Andrei's
scope guard could be used to great avail here. It should be
possible to modify it to something along the lines of:

foo ;
ON_ERROR( foo cleanup ; )
bar ;
ON_ERROR( bar cleanup ; )
// ...
 
K

Kira Yamato

[...]
Two guiding principles, IMNO:

-- I like to keep the try blocks as small as possible, in order
to keep the error handling code as near to the source of the
error as possible.

Interesting. I would think exception handling codes are about the
exceptions to the normal flow of logic. Hence I would move it out of
the code logic. In another word, try to keep the try blocks as large
as possible.

Further, keep the try blocks as small as possible would likely cost a
run-speed penalty for setting up the try-blocks so often.

Of course, if an exception is expected to happen a lot, then perhaps it
shouldn't be implemented as a C++ exception to begin with. If that is
the case, make explicit codes in the normal logic to handle these cases.

These are just my humble opinions.
-- If a variable will not meet the required invariants in the
catch clause, or after, its definition belongs in the try
block.

Can you clarify a bit what you mean by "invariants in the catch clause?"
 
G

Gerhard Fiedler

Interesting. I would think exception handling codes are about the
exceptions to the normal flow of logic. Hence I would move it out of
the code logic. In another word, try to keep the try blocks as large
as possible.

I guess that depends on other criteria, too. Say you have a library that
throws on certain conditions. You know you can and want to handle this
condition locally. But the calls in the whole code snippet in question may
throw all kinds of other stuff that's mostly fatal. So I'd create a
try/catch block around that library call, catching the condition I can and
want handle locally, and anything else I just let throw its way up the call
chain. This would be an example where it makes sense to keep the try block
as small as possible.

Gerhard
 
E

Erik Wikström

Can you clarify a bit what you mean by "invariants in the catch clause?"

Consider something like this:

class Bar;

//...

Bar b;
try {
// modify b
}
catch(exception& e) {
// Can I be sure that b is in a "good" state here?
}

If I can not be sure it will be in a known, good and usable state (its
invariants are preserved) in the catch-block then the declaration of b
should be in the try-clock as well.
 
D

dave_mikesell

In the example I assume that foo, bar, and baz can not throw, only
somecode can. So the question could be reformulated as: is there any
value in including more code than that which can throw, or that which
depends on successful execution of the code that can throw, in the try
block?

If there are several calls that can throw interleaved with ones that
cannot, I'm inclined to put everything in one try/catch block as
opposed to several smaller try/catch blocks. Personal preference,
IMO.
 
J

Joe Greer

(e-mail address removed) wrote in (e-mail address removed):
If there are several calls that can throw interleaved with ones that
cannot, I'm inclined to put everything in one try/catch block as
opposed to several smaller try/catch blocks. Personal preference,
IMO.

Well, if I am just going to bail, I would rather not have a try/catch at
all. If I am going to try to correct something, I would be afraid of not
having enough info if I put everything in the try block. I suppose each
case varies by the kinds of exceptions you are trying to handle.

joe
 
J

James Kanze

On 2008-02-08 03:50:51 -0500, James Kanze <[email protected]> said:
[...]
Two guiding principles, IMNO:
-- I like to keep the try blocks as small as possible, in order
to keep the error handling code as near to the source of the
error as possible.
Interesting. I would think exception handling codes are about the
exceptions to the normal flow of logic. Hence I would move it out of
the code logic. In another word, try to keep the try blocks as large
as possible.
Further, keep the try blocks as small as possible would likely cost a
run-speed penalty for setting up the try-blocks so often.

I should have been clearer. In general, of course, the reason
you report errors with an exception, and not with a return code,
is because you don't expect them to be handled immediately. The
exception should propagate up to a much higher level. In that
sense, the try block is about as far as you can get from the
code which generated the error.

The way I understood the question, however, is that there was a
need for a catch block before leaving the immediate context, in
order to do some cleaning up. In such cases, supposing that a
catch block really is necessary (because in general, I find it
preferable to handle the clean up with destructors), the try
block should be as small as possible, so that it is clear
exactly what is being cleaned up, or what we are cleaning up
from.
Can you clarify a bit what you mean by "invariants in the
catch clause?"

The classical case is a constructor which fails. In that case,
of course, the declaration must be in the try block, or the
exception won't get caught. But you can imagine similar
situations:

SomeType* p ;
try {
p = new SomeType ; // may throw...
// ...
} catch ( ... ) {
// ...
}

In a case like this, the definition of p should obviously be in
the try block.

There are doubtlessly other cases, which are less obvious.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top