Well, I don't really view it as "random" catch site. I put a catch on
anything that throws.
Bad Thing (TM).
Error codes are for communication with the immediate caller. Exceptions are
for communication long distance. Several callers upward typically. It is
like checking passports on every corner instead of doing that only at the
country borders.
1) A dll that contains multithreaded code that is part of a window's
service contains a method that uses boost::lexical_cast on a string
that came in as a parameter.
I'd surround the lexical cast with a try-catch. If boost threw, I
create an error message complaining that the parameter contained
invalid text, log it, and throw a (company made) invalid argument
exception.
Converting exceptions to others is fair in itself. It may be good too, if
you have that single use of the boost facility. However if your DLL uses
boost profoundly, you better use try blocks on your dllexport functions. And
leave the whole implementation alone.
2) Same scenario except I am casting a static constant integer to a string.
My argument is that later on that static constant integer may no
longer be. The design is changing, things get edited all the time, and
I don't see the harm in providing some clarity for the next guy that
"hey boost can throw here!", rather than leaving them to look up every
single function call in various referenced and checking if they throw
or not.
The more the implementation changes the less you want to maintain the
avalanche. Exception are, uh, exceptional. (provided a correct design).
Normally when you're hit by one, you can't do much but cancel a full
high-level operation (or the whole process). Consequently it is enough to
handle them at those few locations. Collectively. And in a simple, stable
way.
As i said, converting from one exception to another is fair, but consider if
there is a benefit really.
Logging is a generic excuse, but IME is way less helpful than claimed. The
natural point is again at the top level, you state the imput params,
possibly the environment and the content of the caught exception. If you
skip that, and only log at a lower point, you'll know what happened but not
why. While having both is mostly redundant.
3) A constructor of an object makes a connection to a database. If the
database connection fails, the object cannot be constructed. Thus, I
throw an exception with a "DB connection failure" error.
Sure. ctors are common exception sources.
I then catch
it in the method that tryed to construct the object.
Why on Earth?
He would argue to let the exception travel on up.
Definitely.
Is DB opening expected? So let the function expect it, and just do its job.
The module dealing with DB can emit arbitrary amount of exceptions,
practically anywhere. If nothing else, SQL timeout is beyond your control,
and can happen in any (otherwise correct) operation. And you have no
realistic way to recover at low level. While on the high level youre not
interested at all which of the 1298 operation failed.
I'd argue that it would be better to
catch it there to let other programmers know that construction can
fail due to a database connection error.
Heh? If you want to teach programmers, do it in the proper institution.
Catching exceptions are not done for teaching puurposes. the only purpose to
catch the exception is to do some relevant action.
In your example action WHAT do you do in the catch block?
A huge problem in this project is that somebody at some time had the
mentality of "if any error occurs anywhere, throw an exception and
don't worry about releasing resources, catching and handling, or
service termination."
Certainly all your functions must bring at least the "basic guarantee" from
the Abrahams classifications.
If that holds, the statement is right: you shall not worry about anything.
Resources are handled by RAII. Exceptions are caught upstream where makes
sense. Your job is to stay out of the way, and do the actual work.
They put some 3rd party library at the top that
catches any unhandled exceptions and logs them.
But they didn't seem
to care about the undefined state it left the system in!
Maybe we're getting somewhere. If the program is in undefned state that is a
problem indeed. But instead of infesting the program with catch clause, you
shall concentrate on that alone: reviwe and reorganize the functions that
are not exception safe.
Hint: it is NOT done using try blocks. But by using RAII, the swap idiom
and stuff like that. mainly by avoiding to mess up the state in the first
place, and break invariants.
I am trying to systematically fix that as I go throw each source file.
I'm still not convinced your fix counts as one. I saw such attempts and
most only pushed the problem and made it subtler, instead of eliminating the
roots. did you ate least some fundamental literatire on exception safety,
and how to reach it in C++? I recently suggested someone to check out
gotw.ca.
To do it at once seems an impossible task. I think a beginning is to
start writing try/catch blocks on a case for case basis and determine
how to handle the error conditions one at a time.
No, the beginning is to learn the fundamental C++ idioms. Aim, set, fire.
Not the other way around.
I'd rather
arbitralilly catch, than arbitrallily let an exception go up the stack
and take it for granted that resources were released and someone else
is catching every flavor of exception and handling it!
If you have non-controlled resources around your fight is futile. And if you
want to fix the situation start RAII-zing the stuff as first step.
However, it seems you might have a different view in that an exception
should be allowed to travel up the stack in some cases where it needs
to be well-defined in the design where they should be handled.
In a healthily organized code you can actually do as your quote above:
return or throw at any (almost) point of the code, and have sensible
outcome. And if the code is not like that, you're doomed anyway.
We don't have any such design in place.
So another starting point is to have it. Actually THAT is the thing that
is supposed to teach and guide the programmers.
So, what does a lowly minion with
barely any input on design, do in that case?
Do you really want my suggestion? In such a situation I would either fix it
in the real sense, or quit for good. Actually did a plenty of both.