Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Exception handling... it's time to fix the standard

3 views
Skip to first unread message

Alexander Terekhov

unread,
May 13, 2003, 11:11:04 AM5/13/03
to
G'Day,

A) http://tinyurl.com/bdp1

"Arrgh! Now I understand why you are unhappy about this.
This goes against everything I'd understood about the way
exceptions worked."

B) <Forward Inline>

<-------- Original Message -------->
Message-ID: <3EC0E634...@web.de>
Newsgroups: comp.lang.c++
Subject: Re: does throw() imply any type of performance difference?

stephan beal wrote:
>
> Hello!
>
> i've got a high-usage class which i'm trying to optimize a bit, and i have a
> question about the throw() clause:
>
> class Foo {
> inline void foo() throw() {...};
> };
>
> Question: does the addition of throw() give a compiler any implicit
> permission (or leeway) to add any sort of exception-handling code to that
> function. More precisely, does the inclusion of this keyword, in and of
> itself, it allow the compiler to make any changes which might affect the
> runtime performance of function foo(), compared to the output generated
> when foo() does not throw()? (The point being, if it does then i want to
> remove them from this particular class.)
>
> i would greatly appreciate any clarification on that point.

Unfortunately, throw() implies [due to totally broken semantics
specified in the {current} C++ standard] a function-try-block with
catch(...) handler that invokes std::unexpected(). Broken standard
aside for a moment(*), throw() really-really helps optimizers. Buy
and read the following paper:

http://www.computer.org/concurrency/pd2000/p4072abs.htm
("C++ Exception Handling", Christophe de Dinechin,
IEEE Concurrency October-December 2000 (Vol. 8, No. 4))

<abstract>
The C++ programming language offers a feature known as exception
handling, which is used, for instance, to report error conditions.
This technique can result in more robust software. On the other
hand, it generally has a highly negative performance impact, even
when exceptions are not actually thrown. This impact is especially
important on an architecture such as the HP/Intel IA-64 processor,
which is very sensitive to compiler optimizations. Hewlett-Packard
implemented exception handling for IA-64 in a way that leaves the
door open for optimizations, even in the presence of exceptions.
</abstract>

regards,
alexander.

The "right" approach is this:

http://groups.google.com/groups?threadm=3EBA6888.D4DF2AB1%40web.de
(Subject: Re: __attribute__((cleanup(function)) versus try/finally)

"....
The current C++ standard says:

"The process of calling destructors for automatic objects
constructed on the path from a try block to a throw-expression
is called 'stack unwinding.'"

That's okay (there's a nice definition of 'try-block' as well).

Now, the current C++ standard also has a couple of kinda-relevant
"implementation-defined" bits:

a) "If no matching handler is found in a program, the function
terminate() is called; whether or not the stack is unwound
before this call to terminate() is implementation-defined",

b) "In the situation where no matching handler is found, it is
implementation-defined whether or not the stack is unwound
before terminate() is called.".

and it also defines the semantics of exception specifications...
in effect, as just a bunch of noop/rethrowing function-try-block
catch-handlers with a trailing catch(...)-thing that invokes
std::unexpected().

I just hate that. To begin with, the definition of the term
'stack unwinding' makes me wonder what "try-block" is meant
here:

int main() {
object o; // <-- 'unwinding' is implementation-defined
throw "trouble";
}

and here:

void Main() throw() {
object o; // <-- 'unwinding' is REQUIRED here
throw "trouble";
}

I believe that in both cases above, std::unexpected() shall
be invoked as the result of successful evaluating of throw-
expression and without any 'unwinding' taking place. Further,
I believe that ALL dtors shall have an implicit throw()-
nothing exception-spec imposed on them. Finally, I believe
that the standard should say that 'execution of each and
every thread' [initial/main including] shall be done "as if"

whatever run(...whatever...) throw(std::thread_exit,
std::thread_cancel);

is called; that implementation simply does finalization
of thread_exit or thread_cancel exception (if thrown)
resulting in thread termination and that any other uncaught
exception will end up in std::unexpected() invoked at throw
point.
...."
</-------- Original Message -------->

C) http://google.com/groups?selm=3C91397A.9FC5F5A4%40web.de
(Subject: Re: C++ and threads)

<quote>

"The process of calling destructors for automatic
objects constructed on the path from a try block
to a throw-expression is called 'stack unwinding.'"

> In the original DCE exception package, which was a set of
> C macros (over setjmp/longjmp),

OK, you probably mean something along the lines of:

ftp://ftp.opengroup.org/pub/dce122/dce/src/threads.tar.gz

"exc handling.h 46591 05/10/96 14:35
exc handling.c 37966 05/10/96 14:35"

> any frame with a TRY/CATCH would unwind even if it had no
> interest in the exception being propagated. That is, it had
> to unwind just to find out.

Question:

Are you saying that it is practically impossible (or perhaps
just pointless/silly) to try to "arrange" the C-macros/
jmp-based exception handling such that when the control
enters the try block/scope you have already "registered"
the "identity" of catch{ all} handlers in the "try context
block" structure as well... so that it could be easily
checked (i.e the presence of next matching handler
somewhere on the "stack") at *throw/re-throw* point(s),
PRIOR to "unwinding"/longjmp-ing to the next frame?

</quote>

Now, what am I missing and/or misunderstanding? TIA.

regards,
alexander.

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

Alexander Terekhov

unread,
May 15, 2003, 5:02:45 PM5/15/03
to

Alexander Terekhov wrote:
[...]

> Finally, I believe
> that the standard should say that 'execution of each and
> every thread' [initial/main including] shall be done "as if"
>
> whatever run(...whatever...) throw(std::thread_exit,
> std::thread_cancel);

Sorry, std::thread_exit_request and std::thread_cancel_request
(std::thread_termination_request aside for a moment ;-) ):

http://groups.google.com/groups?selm=3EC258F8.AE7DF214%40web.de

<quote>

I can see nothing in the POSIX standard that would prohibit
the following implementation of pthread_exit():

extern "C" void pthread_exit(void * ptr) {
std::thread_exit(ptr);
}

using something along the lines of: (from the "std" namespace)

class thread_termination_request : public std::exception ...
class thread_cancel_request : public std::thread_termination_request ...
class thread_exit_request : public std::thread_termination_request ...

template<typename T>
class thread_exit_value : public std::thread_exit_request ...

template<typename T>
void thread_exit(T value) {
assert(std::thread_self().can_exit_with<T>());
throw thread_exit_value(value);
}

</quote>

>
> is called; that implementation simply does finalization
> of thread_exit or thread_cancel exception (if thrown)
> resulting in thread termination and that any other uncaught
> exception will end up in std::unexpected() invoked at throw
> point.

I forgot to mention:

- make std::unexpected handlers thread-specific (keep
std::terminate handers "enclave-wide")

- get rid of the totally broken "if called by the
implementation" clause in 18.6.2.4/2. Details can
be found in a thread here: <http://tinyurl.com/btje>
(with std::unexpected invoked at throw point, there
will be no difference at all with respect "if called
by the program" or by the implementation)

- "weaken" function-try-block handlers for non-dtors
(having implicit throw() ES, function-try-block for
a dtor doesn't make sense). "weaken" means that it
shall be "invisible" in the search phase and have
"dtor-like" semantics during unwinding ala(*):

<copy&paste>

I'll admit that I'll have no problems with something like

template<class _FwdIt, class _Tval> inline
void _Uninit_fill(_FwdIt _First, _FwdIt _Last, const _Tval& _Val,
_Nonscalar_ptr_iterator_tag)
{ // copy _Val throughout raw [_First, _Last), arbitrary type
_FwdIt _Next = _First;
try {
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
}
action_on_propagation_of(...) { /* THIS DOESN'T CATCH *UNEXPECTED* EXCEPTIONS */
/* THIS DOES RETHROW EXCEPTIONS AUTOMATICALLY */
/* NOTHING ELSE CAN BE THROWN FROM THIS SCOPE */
for (; _Next != _First; ++_Next)
_Destroy(&*_Next);
}
}

</copy&paste>

more info on this: <http://tinyurl.com/bthu>.

Alexander Terekhov

unread,
May 25, 2003, 10:18:56 AM5/25/03
to
< "self-correction" [well, and "move up" ;-) ] >

> > Finally, I believe
> > that the standard should say that 'execution of each and
> > every thread' [initial/main including] shall be done "as if"
> >
> > whatever run(...whatever...) throw(std::thread_exit,
> > std::thread_cancel);
>
> Sorry, std::thread_exit_request and std::thread_cancel_request
> (std::thread_termination_request aside for a moment ;-) ):
>
> http://groups.google.com/groups?selm=3EC258F8.AE7DF214%40web.de
>
> <quote>
>
> I can see nothing in the POSIX standard that would prohibit
> the following implementation of pthread_exit():
>
> extern "C" void pthread_exit(void * ptr) {
> std::thread_exit(ptr);
> }

Sorry, I meant:

#define PTHREAD_CANCELED std::thread_canceled()

extern "C" void pthread_exit(void * ptr) throw(std::thread_termination_request) {
(ptr == PTHREAD_CANCELED) ? std::thread_cancel() : std::thread_exit(ptr);
}

>
> using something along the lines of: (from the "std" namespace)

struct thread_canceled {
operator void * () { return &unique; }
static thread_canceled unique;
};

>
> class thread_termination_request : public std::exception ...
> class thread_cancel_request : public std::thread_termination_request ...
> class thread_exit_request : public std::thread_termination_request ...
>
> template<typename T>
> class thread_exit_value : public std::thread_exit_request ...
>
> template<typename T>
> void thread_exit(T value) {
> assert(std::thread_self().can_exit_with<T>());
> throw thread_exit_value(value);
> }

template<>
void thread_exit(std::thread_canceled) {
thread_cancel();
}

void thread_cancel() {
throw std::thread_cancel_request();
}

("or something like that").

regards,
alexander.

--
"Stroustrup is not a disinterested party in that debate."

-- [Subject: Re: c#] http://tinyurl.com/ckem

Terje Slettebø

unread,
May 27, 2003, 1:21:02 PM5/27/03
to
"Alexander Terekhov" <tere...@web.de> wrote in message
news:3EC0ECAA...@web.de...

I've read through your postings, but as they are long and detailed, with a
lot of references to other places, but without some kind of introduction
or summary, I found it hard to understand what your point was.

Could you have tried to restate what it is, in a introduction/summary
form?

This may also have contributed to lack of feedback to this thread, so far.


Regards,

Terje

Alexander Terekhov

unread,
May 27, 2003, 4:55:42 PM5/27/03
to

"Terje Slettebø" wrote:
>
> "Alexander Terekhov" <tere...@web.de> wrote in message
> news:3EC0ECAA...@web.de...
>
> I've read through your postings, but as they are long and detailed, with a
> lot of references to other places, but without some kind of introduction
> or summary, I found it hard to understand what your point was.
>
> Could you have tried to restate what it is, in a introduction/summary
> form?

As currently specified, exception specs not only catch unexpected
exceptions, but they also invoke "wrong" unexpected/terminate
handlers -- those that were in effect at throw-points (handlers
basically fly together with the unexpected exceptions). I want to
have the standard-mandated 2-phase exception processing with the
exception specs acting as simple "barriers" during the 1st/search
phase. All unexpected/uncaught exceptions should result in the
invocation of std::unexpected() at their throw-points; that's due
to the implicit restrictive ESes that I want to be given to all
destructors [throw()] and "threads" -- those should only throw
thread cancel/exit exceptions (things like exceptions with
throwing copy constructors, thowing atexit() handlers, and etc.
aside for a moment]. More "refinements" can be done if/once we
agree on that.

regards,
alexander.

apm

unread,
May 30, 2003, 2:15:26 PM5/30/03
to
tere...@web.de (Alexander Terekhov) wrote in message news:<3ED3AE8B...@web.de>...

> "Terje Sletteb " wrote:
> I want to
> have the standard-mandated 2-phase exception processing with the
> exception specs acting as simple "barriers" during the 1st/search
> phase. All unexpected/uncaught exceptions should result in the
> invocation of std::unexpected() at their throw-points; that's due
> to the implicit restrictive ESes that I want to be given to all
> destructors [throw()]

The difficulty is in having stronger ESes that work in the presence of
templates such as those used in the STL. See
http://www.andrewmarlow.co.uk/publications.html for a proposal on
stronger ESes including a discussion of these, and other, issues.

Regards,

Andrew M.

Alexander Terekhov

unread,
May 30, 2003, 4:01:36 PM5/30/03
to

apm wrote:
>
> tere...@web.de (Alexander Terekhov) wrote in message news:<3ED3AE8B...@web.de>...
> > "Terje Sletteb " wrote:
> > I want to
> > have the standard-mandated 2-phase exception processing with the
> > exception specs acting as simple "barriers" during the 1st/search
> > phase. All unexpected/uncaught exceptions should result in the
> > invocation of std::unexpected() at their throw-points; that's due
> > to the implicit restrictive ESes that I want to be given to all
> > destructors [throw()]
>
> The difficulty is in having stronger ESes that work in the presence of
> templates such as those used in the STL.

Show me an example illustrating "the difficulty" with respect to
*destructors* having stronger (throw()-nothing) ESes, please.

> See
> http://www.andrewmarlow.co.uk/publications.html for a proposal on
> stronger ESes including a discussion of these, and other, issues.

Uhmm, http://www.marlowa.plus.com/publications.html perhaps?

http://www.marlowa.plus.com/goodies/proposal.pdf
(A proposal to add static checking to C++ exception specifications.)

I'm NOT asking for "an extension to C++ in the area of exception
handling that is designed to facilitate static checking of
exceptions."

I can bombard-you-to-death with links on that, but I'll refrain.
(hoping that you'll take a chance and try to understand what I'm
talking about in this thread ;-) )

regards,
alexander.

0 new messages