|
Boost : |
From: Alexander Terekhov (terekhov_at_[hidden])
Date: 2002-08-20 10:27:05
Peter Dimov wrote:
[...]
> Whether you spell your try block as try {} or as "throw()" doesn't really
> matter.
< Forward Inline >
-------- Original Message --------
Message-ID: <3D625EDA.20377582_at_[hidden]>
From: Alexander Terekhov <terekhov_at_[hidden]>
Subject: Re: High level thread design question
Newsgroups: comp.programming.threads
Date: Tue, 20 Aug 2002 17:23:06 +0200
Peter Dimov wrote:
>
> Alexander Terekhov <terekhov_at_[hidden]> wrote in message news:<3D613D44.9B67916_at_[hidden]>...
> > Peter Dimov wrote:
> > [...]
> > > What is brain dead, the concept or the implementation?
> >
> > The concept. I, personally, really don't like the idea of propagating
> > std::logic_error (and alike beasts) across threads on join -- ideally,
> > I want it to kill the process at throw point, unless someone really
> > wants to pretend that s/he can "recover" from it and catch it for that
> > or some other (most likely silly) reason;
>
> You can put an exception specification that prohibits std::logic_error
> on the threadproc (and hope that it doesn't unwind ;-) .)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Peter, I'm going to IGNORE your wink. ;-) That's rather serious
issue/design flaw in the current C++ language, I believe strongly.
To others: IT'S HOPELESS! Unfortunately, brain-dead unwinding on
ES violations IS THE STANDARD REQUIRED "FEATURE" in the current
C++ language ("The C++ Programming Language", 3rd Edition, Bjarne
Stroustrup [but annotations are mine]):
</quote>
14.6 Exception Specifications
Throwing or catching an exception affects the way a function
relates to other functions. It can therefore be worthwhile to
specify the set of exceptions that might be thrown as part of
the function declaration.
For example:
void f(int a) throw ( x2, x3 );
This specifies that f() may throw only exceptions x2, x3, and
exceptions derived from these types, but no others. When a
function specifies what exceptions it might throw, it effectively
offers a guarantee to its callers. If during execution that
function does something that tries to abrogate the guarantee,
the attempt will be transformed into a call of std::unexpected().
The default meaning of unexpected() is std::terminate(), which
in turn normally calls abort(); see §9.4.1.1 for details.
In effect,
void f() throw ( x2, x3 )
{
// stuff
}
is equivalent to:
^^^^^^^^^^^^^^^^^ <annotation>
a) IT IS NOT "is equivalent to:" -- pls see the
next annotation below (it's simply the second
major flaw; after the general idea to always
unwind unexpected things... partially hiding
behind rather silly "On other systems, it is
architecturally close to impossible not to
invoke the destructors while searching for a
handler" argument[1]. (quoted from: Section
14.7, Uncaught Exceptions, TC++PL)
b) copying/constructing temporary ("x2" or "x1")
caught exception object aside; BTW, I really
prefer to catch "const refs" (for "class type"
exceptions)
</annotation>
void f()
try
^^^ <annotation>
that's "function-try-block" -- pretty useless thing, and
only good for "translating"/"logging"/"attach something to"
exceptions thrown from c-tors and d-tors (but d-tors should
normally NOT throw)... And, of course, it *WORKS JUST FINE*
w.r.t. brain-dead catch(...)->unexpected() unwinding on ES
violations! ;-) Well, actually, it's >>UTTERLY BRAIN-DEAD<<
(and IS NOT "is equivalent to:", to begin with) given that
the current language simply BREAKS "RAII model" with respect
to user specified (using RAII do/undo objects) terminate()
and unexpected() handlers (when hitting ES "barriers";
"implementation-defined" unwinding on uncaught exceptions
aside for a moment):
http://groups.google.com/groups?selm=m.collett-E982F8.12450216072002%40lust.ihug.co.nz
http://groups.google.com/groups?threadm=3D3547BE.3045A2A6%40web.de
(Subject: Re: Is internal catch-clause rethrow standard?)
</annotation>
{
// stuff
}
catch (x2) { throw; } // re-throw
catch (x3) { throw; } // re-throw
catch (...) {
std::unexpected(); // unexpected() will not return
}
The most important advantage is that the function declaration
belongs to an interface that is visible to its callers. Function
definitions, on the other hand, are not universally available.
Even when we do have access to the source code of all our
libraries, we strongly prefer not to have to look at it very
often. In addition, a function with an exception-specification
is shorter and clearer than the equivalent hand-written version.
A function declared without an exception-specification is
assumed to throw every exception.
For example:
int f(); // can throw any exception
A function that will throw no exceptions can be declared with
an empty list:
int g() throw(); // no exception thrown
</quote>
regards,
alexander.
[1] http://groups.google.com/groups?threadm=3C91397A.9FC5F5A4%40web.de
(Subject: Re: C++ and threads)
P.S. http://lists.boost.org/MailArchives/boost/msg34156.php
([boost] Re: Attempting resolution of Threads & Exceptions Issue)
"....
In my view, there should be NO difference whatsoever between
"no-handler-found" and hitting some exception propagation barrier
[ES, d-tor that is unwound itself, etc.] -- that everything should
result in calling unexpected() AT THROW POINT (no stack unwinding;
two phase processing).
...."
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk