"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 ]
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>.
> > 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
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
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.
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.
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.