|
Boost : |
From: Msk_at_[hidden]
Date: 2001-11-14 10:09:21
--- In boost_at_y..., "David Abrahams" <david.abrahams_at_r...> wrote:
> > > Msk_at_X... wrote:
> > > >
> > > > if( num_widgets > max_widgets )
> > > > {
> > > > throw logic_error(
> > > > BOOST_ERROR_MESSAGE << "num_widgets = " <<
> > > > num_widgets << " is greater than maxwidgets = " <<
> > > > max_widgets );
> > > > }
> > > >
> <snip>
> > our programmers can write simple statements like:
> >
> > VERIFY( p!=0, "no widget supplied" );
> > VERIFY( p->m_status==normal,
> > "abnormal widget, state = " << p->m_status );
>
> My 2 cents: I worry a little about any error detection mechanism
that
> requires the allocation of resources. In particular, this streaming
> interface looks on the surface like it could throw an exception
before the
> intended error is reported.
>
> -Dave
Yes, it can do exactly that, so the resource allocation bothers
me too. However, what we found in our group was that it is
difficult to change programmer habits and culture, and without
something like this people just didn't include all the checks
that they should in their code. With it (and a bit of peer
pressure), they did.
The total net effect on quality was quite positive, so we accepted
the small risk of something going wrong during error handling. It
is a compromise, but not nearly as bad as it sounds at first:
Let's say that you detect a bad widget, and you start building
a message to report that. While doing so, some resource allocation
fails inside your streaming or string operations. Presumably
that causes an exception to be thrown. Because it is generated at
a lower abstraction level this "secondary" exception will not use the
streaming formatting, so there is no risk of infinite recursion.
The fact that resource allocation failed means you already had a
problem and just didn't know it yet. Therefore, the exception that
gets thrown simply reports the resource problem instead of the widget
problem. If you argue that "almost out of resources" is an error
condition, you could even claim that the resource error existed
_before_
the widget error was detected, and so it _should_ be the one reported.
Since the secondary throw was triggered before the first one ever
executed, there are no weird language effects. The bottom line is
that
you simply end up reporting a (legitimate) error that is different
from the one you originally intended to report. Not perfect, but we
found it acceptable, and after a couple of years of 24x7 operation of
multiple processes on multiple machines, I don't think we've ever
identified an actual case where this happened. (The code currently
in production doesn't use stringstreams, but it does have the same
basic potential for resource exhaustion during processing.)
Also, the availability of this mechanism doesn't _force_ you to
use it everywhere. If there are a few particular places in your
code where for some reason you cannot tolerate the secondary throw
problem, you can just pass a "C-style string", or sprintf() into
a static buffer.
For what it's worth, the only major headache we had in making this
stuff work reliably was not in the formatting but in the logging --
what
happens if the file is momentarily locked, the disk is full, another
thread is writing to the log, the program or machine crashes before
the disk buffer is flushed, etc. etc. We never had more than minor
problems in the formatting, but it took us months to get the logging
code really solid. (A Mean Time Between Failure of a few weeks of
runtime was not good enough in our environment, so we were pretty
demanding about what constituted "solid".)
- Michael Kenniston
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk