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

Is internal catch-clause rethrow standard?

11 views
Skip to first unread message

Alf P. Steinbach

unread,
Jul 10, 2002, 6:44:31 AM7/10/02
to
A few years ago a clever technique for implementing a more-
or-less generic exception filter, transforming exceptions
to std::exception, was suggested in this group (CLC++M),
functionally equivalent to


catch( ... )
{
try
{
throw;
}
catch( TypeA const& x )
{
throw MyStdException( x );
}
catch( TypeB const& x )
{
throw MyStdException( x );
}
// Etc.
catch( ... )
{
throw MyStdException( "Unknown inner exception" );
}
}


At the time there was much discussion about what this technique
"should" be used for, but it all stopped when Andrei pointed out
that Visual C++ 6.0 -- or was it 5.0? -- doesn't support
this construction.

Is internal catch-block rethrow support required by the std?

Note: in practice the inner try-catch block would reside in a
separate function called from the outer catch.

- Alf

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

David Abrahams

unread,
Jul 10, 2002, 3:07:57 PM7/10/02
to

"Alf P. Steinbach" <alf_p_s...@yahoo.no> wrote in message
news:3d2be46c...@news.online.no...

> A few years ago a clever technique for implementing a more-
> or-less generic exception filter, transforming exceptions
> to std::exception, was suggested in this group (CLC++M),
> functionally equivalent to
>
>
> catch( ... )
> {
> try
> {
> throw;
> }
> catch( TypeA const& x )
> {
> throw MyStdException( x );
> }
> catch( TypeB const& x )
> {
> throw MyStdException( x );
> }
> // Etc.
> catch( ... )
> {
> throw MyStdException( "Unknown inner exception" );
> }
> }
>
>
> At the time there was much discussion about what this technique
> "should" be used for, but it all stopped when Andrei pointed out
> that Visual C++ 6.0 -- or was it 5.0? -- doesn't support
> this construction.

That's not quite accurate. VC++6 will compile it, but will generate
incorrect code: the exception object being re-thrown will be destroyed
twice. If you're going to use this idiom with VC6, you need to exercise some
discipline about the way you write your exception classes so that they are
immune to double-destruction. It's generally pretty easy to do that.

> Is internal catch-block rethrow support required by the std?

Yes.

-Dave

Rune Huseby

unread,
Jul 10, 2002, 3:12:17 PM7/10/02
to
On 2002 07.10 12:44, alf_p_s...@yahoo.no (Alf P. Steinbach) wrote:

> A few years ago a clever technique for implementing a more-
> or-less generic exception filter, transforming exceptions
> to std::exception, was suggested in this group (CLC++M),
> functionally equivalent to

[...]

>
>
> At the time there was much discussion about what this technique
> "should" be used for, but it all stopped when Andrei pointed out
> that Visual C++ 6.0 -- or was it 5.0? -- doesn't support
> this construction.

I avoid using catch(...) in VC 6 since it catches _all_ exceptions.
Including NT exceptions like access violations and division by zero. Some
of these exceptions is of such a nature that the application should die
instead of handling it generically.

> Is internal catch-block rethrow support required by the std?

I don't know about this.


--
Rune Huseby

Alexander Terekhov

unread,
Jul 11, 2002, 7:17:59 AM7/11/02
to

Rune Huseby wrote:
[...]

> I avoid using catch(...) in VC 6 since it catches _all_ exceptions.

That's what catch(...) is all about, MS bugs [and SEH 'integration']
aside. If you have implementation that 'supports' ex.specs, try this:

void
operation();

/**/

void
fenced_operation_invocation()
throw(
/* I REALLY >>REALLY<< WANT CATCH THESE EXCEPTIONS *
* AND, PLEASE, >>PLEASE<< IN ANY EVENT, DON'T ADD *
* 'mothers-of-all-exceptions' like std::exception *
* and/or std::bad_exception !!!!!!!!!!!!!!!!!!!!! */
blah,
blahblah
/* etc. */
)
{
operation();
}

/**/
try {
fenced_operation_invocation();
}
catch(...) {

// 'recovers' exception type/info via 'try-rethrow-catch'
handle_fenced_operation_exceptions();

}

Oh, Ah, if/when you meet Abrahams/Sutter/etc., please tell'm that
"implementation-defined" unwinding-to-nowhere for uncaught exceptions
[lack of *mandatory* TWO-PHASE processing] and the 'khm' way how the
standard *requires* unwinding in order to 'detect' ex.specs. violation
on *archaic* setjmp/longjmp 'C-macros' exceptions implementations [w/o
f.ex. handlers-identity registration prior to entering try scopes that
would allow checking/search w/o unwinding] is... well, 'BS', IMHO|sorry.

regards,
alexander.

Allan W

unread,
Jul 12, 2002, 7:16:02 AM7/12/02
to
Alexander Terekhov <tere...@web.de> wrote

> Oh, Ah, if/when you meet Abrahams/Sutter/etc., please tell'm that
> "implementation-defined" unwinding-to-nowhere for uncaught exceptions
> [lack of *mandatory* TWO-PHASE processing] and the 'khm' way how the
> standard *requires* unwinding in order to 'detect' ex.specs. violation
> on *archaic* setjmp/longjmp 'C-macros' exceptions implementations [w/o
> f.ex. handlers-identity registration prior to entering try scopes that
> would allow checking/search w/o unwinding] is... well, 'BS', IMHO|sorry.

I'm having trouble parsing this extremely-long sentence, and not just
because of the random 'quoting' you do. What does this sentence mean?
Specifically:
* Why do you single out "Abrahams/Sutter/etc"
* What is "unwinding-to-nowhere"
* What is TWO-PHASE processing and why should it be *mandatory*
* What is the 'khm' way how
* does try/catch require "handlers-identity registration" prior to
entering try scopes

Sorry if I'm just too dumb to understand... I'd appreciate any
illumnation you can provide.

Alexander Terekhov

unread,
Jul 12, 2002, 10:12:27 PM7/12/02
to

Allan W wrote:
>
> Alexander Terekhov <tere...@web.de> wrote
> > Oh, Ah, if/when you meet Abrahams/Sutter/etc., please tell'm that
> > "implementation-defined" unwinding-to-nowhere for uncaught exceptions
> > [lack of *mandatory* TWO-PHASE processing] and the 'khm' way how the
> > standard *requires* unwinding in order to 'detect' ex.specs. violation
> > on *archaic* setjmp/longjmp 'C-macros' exceptions implementations [w/o
> > f.ex. handlers-identity registration prior to entering try scopes that
> > would allow checking/search w/o unwinding] is... well, 'BS', IMHO|sorry.
>
> I'm having trouble parsing this extremely-long sentence, and not just
> because of the random 'quoting' you do. What does this sentence mean?
> Specifically:
> * Why do you single out "Abrahams/Sutter/etc"

Red herring. Well,

http://groups.google.com/groups?selm=230879.F56DA7E1%40web.de
("protection", "IOW, I believe strongly that...", etc.)

> * What is "unwinding-to-nowhere"
> * What is TWO-PHASE processing and why should it be *mandatory*

http://groups.google.com/groups?selm=3CFB9FF7.76D1109A%40web.de
http://groups.google.com/groups?selm=3CFC6591.870B42A%40web.de
http://groups.google.com/groups?selm=3CFC66B9.4C7B17AC%40web.de
http://groups.google.com/groups?selm=3CC434E6.8FE3804C%40web.de
http://groups.google.com/groups?selm=3CC45475.BF5A69D2%40web.de
http://groups.google.com/groups?selm=08A049.6850244E%40web.de

> * What is the 'khm' way how

http://groups.google.com/groups?selm=3C7633AF.4A08EFBF%40web.de

> * does try/catch require "handlers-identity registration" prior to
> entering try scopes

http://groups.google.com/groups?selm=3C91397A.9FC5F5A4%40web.de
("OK, you probably mean something along the lines of...")

> Sorry if I'm just too dumb to understand... I'd appreciate any
> illumnation you can provide.

HTH.

regards,
alexander.

P.S. http://www.opengroup.org/sophocles/show_mail.tpl?source=L&listname=austin-group-l&id=4300
([Re: abort() and async-signal safety] "...all I want is simply...")

Francis Glassborow

unread,
Jul 13, 2002, 8:44:48 PM7/13/02
to
In article <3D2EDF6C...@web.de>, Alexander Terekhov
<tere...@web.de> writes

Could you please answer the question. I followed the link, and, probably
because of my advanced age induced stupidity, am still none the wiser.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Jim Hyslop

unread,
Jul 13, 2002, 8:47:57 PM7/13/02
to
In article <3D2D495E...@web.de>, tere...@web.de says...

>
> Rune Huseby wrote:
> [...]
> > I avoid using catch(...) in VC 6 since it catches _all_ exceptions.
>
> That's what catch(...) is all about, MS bugs [and SEH 'integration']
> aside.
No, catch(...) is about catching a C++ exception. MSVC allows it to
catch a hardware exception - and this has cost us no end of grief,
because we're writing code that has to run on both Windows and an
embedded system, which does _NOT_ provide structured exception handling.
It wouldn't be such a big deal IF I could turn off MSVC's structured
exceptions, but I can't (easily - yes I know there are ways to do it,
but none of them are particularly easy..

Worse, we recently had a "Pure Virtual Function Called" crash - that
only happened in release mode on the Windows platform, not in debug
mode. Eventually, we tracked it down to code that essentially did this:

class ABC
{
public:
void somePureFunction() = 0;
};

class Concrete : public ABC
{
public:
void somePureFunction();
};

void oops()
{
Concrete * cp = new Concrete;
delete cp;
cp->somePureFunction();
}

In debug mode, the compiler overwrites memory that is deallocated with a
sentinel value (0xDD, IIRC). So when cp got deleted, its vptr got set to
0xDDDDDDDD. When the program tried to read the vtable to look up
somePureFunction, of course it threw an access violation - which was
promptly absorbed by the nearest "catch (...)" statement. In release
mode, though, the memory is simply returned to the heap as-is. By that
time, cp's vptr points to the ABC vtable - which has a pure virtual
function entry.

We cannot eliminate the "catch(...)" handlers - as I said, one of the
platforms for this software is an embedded system that cannot allow
unhandled exceptions.

> If you have implementation that 'supports' ex.specs, try this:

Are there any implementations besides MSVC that support structured
exceptions?

--
Jim

David Abrahams

unread,
Jul 14, 2002, 1:43:14 PM7/14/02
to

"Jim Hyslop" <jhy...@ieee.org> wrote in message
news:MPG.17995092a...@news1.on.sympatico.ca...


> In article <3D2D495E...@web.de>, tere...@web.de says...

> No, catch(...) is about catching a C++ exception. MSVC allows it to


> catch a hardware exception - and this has cost us no end of grief,

<snip>

You can protect yourself from most of these effects with MSVC via this hack:

# pragma warning(push)
# pragma warning(disable:4297)
extern "C" void structured_exception_translator(unsigned int,
EXCEPTION_POINTERS*)
{
throw;
}
# pragma warning(pop)

extern "C" { typedef void (*translator)(unsigned int,
EXCEPTION_POINTERS*); }
translator x = _set_se_translator(structured_exception_translator);

That will keep catch(...) clauses from interfering with structured
exceptions (unless those SEs are themselves thrown from within a catch
block).

> Are there any implementations besides MSVC that support structured
> exceptions?

Metrowerks CodeWarrior does. Better yet, you can use a
"zero-runtime-overhead" C++ EH model which eliminates the egregious
overheads imposed by SEH for C++ exceptions and in which C++ exceptions and
structured exceptions are completely separate beasts.

-Dave

Alexander Terekhov

unread,
Jul 15, 2002, 4:58:20 PM7/15/02
to
< no.it... replaced with c.p.t. ;-) >

Jim Hyslop wrote:
>
> In article <3D2D495E...@web.de>, tere...@web.de says...
> >
> > Rune Huseby wrote:
> > [...]
> > > I avoid using catch(...) in VC 6 since it catches _all_ exceptions.
> >
> > That's what catch(...) is all about, MS bugs [and SEH 'integration']
> > aside.

> No, catch(...) is about catching a C++ exception.

Again, catch(...) is about catching ALL exception [>>C<< exceptions,
aka SEH, *including*]. ;-)

> MSVC allows it to catch a hardware exception - and this has cost us
> no end of grief,

There are many-many other exceptions that could "cost us no end of
grief" if propagated/caught blindly.

> because we're writing code that has to run on both Windows and an
> embedded system, which does _NOT_ provide structured exception handling.
> It wouldn't be such a big deal IF I could turn off MSVC's structured
> exceptions, but I can't (easily - yes I know there are ways to do it,
> but none of them are particularly easy..

SEH/C-exceptions [Java/Ada/Whatever exceptions] should better be
"integrated" via some common calling standard exception support
conventions [platform] standard and library with "foreign-exceptions-
personalization" [sort-of handles] in ANY language/runtime that provides
exceptions; C++ language/runtime *especially*, IMNSHO.

> Worse, we recently had a "Pure Virtual Function Called" crash - that
> only happened in release mode on the Windows platform, not in debug
> mode. Eventually, we tracked it down to code that essentially did this:

[...]


> of course it threw an access violation - which was
> promptly absorbed by the nearest "catch (...)" statement.

Ha! I'd be extremely careful with catch(...) AND with all other
"catch-whatever" idioms such as catch(const std::exception&)!!!

> In release
> mode, though, the memory is simply returned to the heap as-is. By that
> time, cp's vptr points to the ABC vtable - which has a pure virtual
> function entry.
>
> We cannot eliminate the "catch(...)" handlers - as I said, one of the
> platforms for this software is an embedded system that cannot allow
> unhandled exceptions.

What exactly do you mean? To me, "reliable" software doesn't mean
that all exceptions should be caught blindly -- there should be an
extra level/layer providing REALLY HIGH availability... things like
*unexpected loss of power* including.

> > If you have implementation that 'supports' ex.specs, try this:

> Are there any implementations besides MSVC that support structured
> exceptions?

Sure, consider:

http://www.testdrive.compaq.com
http://tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_PDF/ARH9RBTE.PDF

----

spe207.testdrive.compaq.com> what /shlib/libpthread.so|grep DECthreads
DECthreads version V3.18-138 May 12 2002
spe207.testdrive.compaq.com> cc -pthread -o seh seh.c
spe207.testdrive.compaq.com> ./seh

Go...

Hi There! Greetings from the ``yellow zone.''

Exception: Attempted stack overflow was detected (dce / thd)

Indeed. ;-)

spe207.testdrive.compaq.com> cat seh.c

#include <stdio.h>
#include <memory.h>
#include <pthread.h>
#include <pthread_exception.h>

void operation()
{
char buffer[128];
memset( buffer, 0, sizeof( buffer ) );
operation();
}

void* my_thread( void* p )
{
TRY {
printf( "\nGo...\n\n" );
operation();
}
CATCH_ALL {
printf( "Hi There! Greetings from the ``yellow zone.''\n\n" );
pthread_exc_report_np( THIS_CATCH );
TRY {
RERAISE;
}
CATCH( pthread_stackovf_e ) {
printf( "\nIndeed. ;-)\n\n" );
}
ENDTRY
}
ENDTRY
return NULL;
}

int main()
{
pthread_t tid;
pthread_create( &tid, NULL, &my_thread, NULL );
pthread_exit( NULL );
}

spe207.testdrive.compaq.com> cc -pthread -c -o seh2c.o seh2c.c
spe207.testdrive.compaq.com> cxx -pthread -o seh2 seh2cpp.cpp seh2c.o
spe207.testdrive.compaq.com> ./seh2

C++ try...

Go...

Hi There! Greetings from the ``yellow zone.''

Exception: Attempted stack overflow was detected (dce / thd)

Indeed. ;-) Ha! >>RERAISE<<

C++ catch(...)

Finished!

spe207.testdrive.compaq.com> cat seh2c.c

#include <stdio.h>
#include <memory.h>
#include <pthread.h>
#include <pthread_exception.h>

void operation()
{
char buffer[128];
memset( buffer, 0, sizeof( buffer ) );
operation();
}

void go()
{
TRY {
printf( "\nGo...\n\n" );
operation();
}
CATCH_ALL {
printf( "Hi There! Greetings from the ``yellow zone.''\n\n" );
pthread_exc_report_np( THIS_CATCH );
TRY {
RERAISE;
}
CATCH( pthread_stackovf_e ) {
printf( "\nIndeed. ;-) Ha! >>RERAISE<<\n\n" );
RERAISE;
}
ENDTRY
}
ENDTRY
}


#include <pthread.h>

#include <iostream>
using namespace std;

extern "C" void go();

extern "C" void* my_thread( void* p )
{
cout << "\nC++ try..." << endl;
try {
go();
}
catch(...) {
cout << "C++ catch(...)" << endl;
}
cout << "\nFinished!\n" << endl;
return 0;
}

int main()
{
pthread_t tid;
pthread_create( &tid, 0, &my_thread, 0 );
pthread_exit( 0 );
}

spe207.testdrive.compaq.com>

----

regards,
alexander.

Alexander Terekhov

unread,
Jul 15, 2002, 5:00:36 PM7/15/02
to

Francis Glassborow wrote:
>
> In article <3D2EDF6C...@web.de>, Alexander Terekhov
> <tere...@web.de> writes
> >> * What is the 'khm' way how
> >
> >http://groups.google.com/groups?selm=3C7633AF.4A08EFBF%40web.de
>
> Could you please answer the question.

Follow the link.

We've got three functions -- a(), b() and c(). Function a() specifies
exceptions that it can throw -- throw( a_bad_exception, /* and let's
say */ Lenin, Stalin ). A_bad_exception beast is thrown by unexpected
handler that is set internally (via RAII "activator" object) -- inside
function a().

Function b() doesn't have exceptions specified; it could throw
anything. Function c() specifies throw( c_bad_exception, /* and
let's say */ Gorby ). C_bad_exception beast is thrown by unexpected
handler that is set internally (via RAII object) -- inside function
c(). Function a() calls b(). Function b() calls c().

Now, imagine that function c() throws Gorby. Gorby flies way up the
stack to the a()'s implicit catch(...) handler injected due to a()'s
ex.specs. C()'s unexpected handler flies together with Gorby. Since
Gorby was not specified in the list of exceptions that can be thrown
from a(), our wonderful implicit catch(...) handler will invoke
unexpected handler that was established inside function c() by the
time Gorby was fired. That unexpected handler will throw
c_bad_exception, but THAT exception is also not allowed to propagate
out of a()... and the program will terminate.

Now try to imagine what would happen if c()'s unexpected handler
would be invoked AT GORBY THROW POINT -- inside function c()... It
(i.e. c()'s unexpected handler) would throw c_bad_exception. Function
b() would catch it via its explicit catch() handler and would either
fully "handle" it or throw "something_else". That "something_else"
could then either:

a) be propagated out of b() and a(); if a() doesn't catch it and
if "something_else" is actually Lenin or Stalin or perhaps
a_bad_exception (and if it's EXPECTED on the "higher" level);

b) result in unexpected handler (established by function a())
being invoked at SOMETHING_ELSE THROW POINT -- inside function
b()... and that would throw a_bad_exception, which COULD well be
propagated out of function b() AND a() (again, if it's EXPECTED
on the "higher" level).

Do you see the point? Or am I missing and/or misunderstanding
something?

regards,
alexander.

Jim Hyslop

unread,
Jul 16, 2002, 5:27:31 AM7/16/02
to
In article <3D32A955...@web.de>, tere...@web.de says...

> < no.it... replaced with c.p.t. ;-) >
>
> Jim Hyslop wrote:
> > No, catch(...) is about catching a C++ exception.
>
> Again, catch(...) is about catching ALL exception [>>C<< exceptions,
> aka SEH, *including*]. ;-)
No. If we were discussing this in a Microsoft-specific forum, then I
would agree with you. As far as I can tell, this discussion is taking
place in forums that are platform-independent. Therefore any discussion
about what a C++ statement means must be in the context of how it is
defined in the standard, and discussion on any platform-specific
extensions should be confined to footnotes.

The standard says "a handler will be invoked only by a throw-exception
invoked in code executed in the handler's try block...." That means a
catch statement can only catch a C++ exception. Anything else is an
extension.

> > MSVC allows it to catch a hardware exception - and this has cost us
> > no end of grief,
>
> There are many-many other exceptions that could "cost us no end of
> grief" if propagated/caught blindly.

In the environment I'm working in (see below) the cost of allowing an
exception to go unhandled vastly outweighs whatever it would cost to
"blindly" catch an exception.

> SEH/C-exceptions [Java/Ada/Whatever exceptions] should better be
> "integrated" via some common calling standard exception support
> conventions [platform] standard and library with "foreign-exceptions-
> personalization" [sort-of handles] in ANY language/runtime that provides
> exceptions; C++ language/runtime *especially*, IMNSHO.

Fine, I agree with this - in principle at least. I don't know how
feasible this would be to implement.

But until this integration happens, non-C++ exceptions are non-standard
and therefore non-portable. MS should IMO provide a better, easier way
to disable non-C++ exceptions.

> [...]
> > of course it threw an access violation - which was
> > promptly absorbed by the nearest "catch (...)" statement.
>
> Ha! I'd be extremely careful with catch(...) AND with all other
> "catch-whatever" idioms such as catch(const std::exception&)!!!

You are presuming we aren't being careful.

> > We cannot eliminate the "catch(...)" handlers - as I said, one of the
> > platforms for this software is an embedded system that cannot allow
> > unhandled exceptions.
>
> What exactly do you mean?

The company I work for produces television broadcast equipment. We
supply equipment to most of the major networks around the world. If you
watched any of the World Cup on TV, the signal you watched passed
through our equipment, some of it at the control room in Korea. Now, if
our equipment suddenly barfed and rebooted at a critical moment because
of an unhandled exception, the CEOs of these aforesaid major networks
would be screaming at my CEO, who would promptly come around handing out
pink slips.

> To me, "reliable" software doesn't mean
> that all exceptions should be caught blindly -- there should be an
> extra level/layer providing REALLY HIGH availability... things like
> *unexpected loss of power* including.

Obviously the software can do nothing about loss of power. That's what
UPSs are for.

But the software *can* - and in our case must - do something about
catching exceptions. All of them. Portably (remember, this software runs
on both Windows and embedded hardware). And this eliminates C exceptions
from our consideration.

> > Are there any implementations besides MSVC that support structured
> > exceptions?
>
> Sure, consider:
>
> http://www.testdrive.compaq.com
> http://tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51A_PDF/ARH9RBTE.PDF

Thanks for the links, I will check them out.

--
Jim

Alf P. Steinbach

unread,
Jul 16, 2002, 5:31:28 AM7/16/02
to
On 15 Jul 2002 16:58:20 -0400, Alexander Terekhov <tere...@web.de>
wrote:

>< no.it... replaced with c.p.t. ;-) >
>

I originated this thread, but this is the first message I've seen
from it... I thought it had just disappeared into some moderator's
junk mail folder (Alf again, drop dead you imbecile!), or something.

Possibly it's because my news-server doesn't currently provide
the comp.programming.* hierarchy?

Anyway, that's why I've not participated in the discussion. I've
therefore taken the liberty of posting this only to CLCPPM.

Q: John Hyslop: thanx for the clarification -- and I remember
the MSVC particulars now -- but (1) exactly how does one
"easily" protect against such double destruction, and (2) can
one be sure that program state (e.g. the stack, internally
registered SEH exception handlers, etc.) is Ok after that?

TIA.,

- Alf

Michiel Salters

unread,
Jul 16, 2002, 5:34:42 AM7/16/02
to
jhy...@ieee.org (Jim Hyslop) wrote in
news:MPG.17995092a...@news1.on.sympatico.ca:

> In article <3D2D495E...@web.de>, tere...@web.de says...
>>
>> Rune Huseby wrote:
>> [...]
>> > I avoid using catch(...) in VC 6 since it catches _all_ exceptions.
>>
>> That's what catch(...) is all about, MS bugs [and SEH 'integration']
>> aside.

> No, catch(...) is about catching a C++ exception. MSVC allows it to
> catch a hardware exception - and this has cost us no end of grief,
> because we're writing code that has to run on both Windows and an
> embedded system, which does _NOT_ provide structured exception handling.
> It wouldn't be such a big deal IF I could turn off MSVC's structured
> exceptions, but I can't (easily - yes I know there are ways to do it,
> but none of them are particularly easy..

I've found that any exception caught by ... but not by a preceding
std::exception& was an error. That is something I treat like a failed
assert, something the running process can't handle not ignore. The only
strategy is to call in external help, either from other components, the OS
or a (human) operator. SEH exceptions are no exception ( pun not intended )

Regards,
--
Michiel Salters

Alexander Terekhov

unread,
Jul 16, 2002, 5:36:05 AM7/16/02
to

David Abrahams wrote:

[snip undocumented hack -- probably won't work under next "pack", anyway]

BTW, somewhere on the MS site [no link this time -- probably won't show up
without that nice just-a-few-characters-lost phenomenon I've experienced
here recently, anyway]:

"....
#pragma managed
void managed_func(void)
{
try
{
RaiseException(MYEXCEPTION_CODE, 0, 0, 0);
}
catch(CMyException x)
{
}
catch(...)
{
printf("This is invoked since _set_se_translator is not supported when /clr is used\n");
}
}
....
#pragma managed
int main(int argc, char** argv)
{
_set_se_translator(my_trans_func);
// it doesn't matter whether the translator function
// is registered in managed or unmanaged code
managed_func();
unmanaged_func();
return 0;
}
...."

[...]


> Better yet, you can use a
> "zero-runtime-overhead" C++ EH model which eliminates the egregious
> overheads imposed by SEH for C++ exceptions and in which C++ exceptions and
> structured exceptions are completely separate beasts.

IMO, you are /still/ thinking in the "wrong" direction, really.

regards,
alexander.

Matthew Collett

unread,
Jul 16, 2002, 4:37:45 PM7/16/02
to
In article <3D326BB4...@web.de>,
Alexander Terekhov <tere...@web.de> wrote:

> C_bad_exception beast is thrown by unexpected
> handler that is set internally (via RAII object) -- inside function
> c(). Function a() calls b(). Function b() calls c().
>
> Now, imagine that function c() throws Gorby. Gorby flies way up the
> stack to the a()'s implicit catch(...) handler injected due to a()'s
> ex.specs. C()'s unexpected handler flies together with Gorby.

> [...] That unexpected handler will throw

> c_bad_exception, but THAT exception is also not allowed to propagate
> out of a()... and the program will terminate.
>

> alexander.

Not if your RAII is doing its job. Unwinding the stack as you leave
c() will call the RAII object's destructor, which should reset the
unexpected handler to whatever it was before entering c(). The
implicit catch(...) in a() that actually _calls_ the unexpected
handler isn't reached until after this resetting has occurred, so
all should be well.

> Or am I missing and/or misunderstanding something?

Or maybe I am ...


Best wishes,
Matthew Collett

--
The word "reality" is generally used with the intention of evoking sentiment.
-- Arthur Eddington

Hillel Y. Sims

unread,
Jul 16, 2002, 4:53:57 PM7/16/02
to

"Jim Hyslop" <jhy...@ieee.org> wrote in message
news:MPG.17995092a...@news1.on.sympatico.ca...
> No, catch(...) is about catching a C++ exception.

std::exception is the path to nirvana (and robust code).

1) Never use catch(...), especially in portable code.
2) Always derive all custom exception-types from std::exception (or
subclass), without exception.
3) Catch all C++ exceptions (where necessary) via catch (std::exception&),
which is guaranteed to work if rule 2 is followed.

catch (std::exception&) is all about catching all C++ exceptions. catch
(...) is specifically about catching anything the platform might possibly
throw at you (such as access violation) that lives on the same native
runtime mechanism on which C++ exception-handling is implemented, without
any knowledge of its context or type. I have read (hopefully carefully
enough) the standard and found nothing which explicitly requires anything
caught by catch(...) to be only something raised by a C++ "throw"
statement.** All this makes it legal for platforms (eg Windows, Tru64 Unix,
OpenVMS) to implement their C++ runtime conveniently on top of the
OS-native SEH exception mechanism, with the result that all SEH exceptions
can be caught in catch(...) blocks. This makes it actually very deceptively
dangerous to use catch(...) as an attempt at achieving nothrow status (such
as in dtors) or for error protection, because that block is likely to be
executed not just upon throw of a C++ exception, but also upon a fatal
corruption of the program state (such as access violation) which is raised
as an SEH exception. This means it is unknowingly possible that it is
already far too late for any attempt at nothrow or error protection. (Error
correction of that sort of error, if any, must happen explicitly via
platform-specific API code, and should not be attempted by ordinary generic
user code.) Even in a nothrow block, capturing a non-C++ fatal process
exception and continuing normal execution after that point as if nothing bad
actually happened is virtually always a Very Bad Thing (especially if you
try to write out some important data somewhere which is possibly unknowingly
corrupted...).

There is a simple way to write correct nothrow code that does not suffer
from this problem. _All_ C++ exceptions (including custom-defined types of
even minimal complexity) must always be inherited from std::exception (or
subclass). Non-std::exception-derived objects (such as int, or char*) should
simply never be thrown. It is just a bad idea to throw any kind of exception
object other than something derived from std::exception. The ultimate base
class of any custom exception hierarchies should always inherit from
std::exception. If you have a third-party library that uses exception
objects that are not derived from std::exception which you cannot correct,
then you're out of luck; you would need to additionally explicitly use
"catch (library::base_exc&)" in all instances to catch those exceptions.
Substitution of catch(...) is not a suitable strategy, as it opens the door
to receive non-C++ exceptions.

Always derive all exception objects from std::exception (or subclass),
without exception. This is the only way to correctly catch all C++
exceptions in one statement without interfering with OS-specific non-C++
mechanisms.

By following this simple and straightforward convention, it makes it
possible in all cases to correctly catch _all_ (and ONLY) C++ exceptions via
one blanket statement (of course, even this is not necessarily completely
safe all the time, but sometimes it is necessary...). C++ language code
cannot and should not attempt to intervene in OS-native non-C++ exceptions
under the vast majority of circumstances, and especially not inadvertent
circumstances (even to try to do cleanup), as it has no inherent knowledge
of OS-native implementation and context.

Observance of the std::exception-or-bust rule provides an easy way to avoid
any need for or ill concerns resulting from use of catch(...).

>MSVC allows [catch (...)] to
> catch a hardware exception

Exactly why we must all avoid it.

> - and this has cost us no end of grief,
> because we're writing code that has to run on both Windows and an
> embedded system, which does _NOT_ provide structured exception handling.
> It wouldn't be such a big deal IF I could turn off MSVC's structured
> exceptions, but I can't (easily - yes I know there are ways to do it,
> but none of them are particularly easy..
>
> Worse, we recently had a "Pure Virtual Function Called" crash - that
> only happened in release mode on the Windows platform, not in debug
> mode. Eventually, we tracked it down to code that essentially did this:
>

[..]


> of course it threw an access violation - which was
> promptly absorbed by the nearest "catch (...)" statement.

A good example of why it is evil.

[..]


>
> We cannot eliminate the "catch(...)" handlers - as I said, one of the
> platforms for this software is an embedded system that cannot allow
> unhandled exceptions.
>

C++ exception-handling cannot correctly handle exceptions that cannot be
caught by a C++-accessible name. If you need to handle non-C++
platform-specific exceptions, then you must use a non-C++ platform-specific
mechanism. This can indeed make it (very much) more difficult to write
robust C++ code for use on environments that do not fully integrate their
native error-handling mechanisms with the C++ exception-handling mechanism.
However, as clearly displayed by your problem above, catch(...) is certainly
not the path to achieving robust high-availability code.


> Are there any implementations besides MSVC that support structured
> exceptions?

Tru64 Unix, OpenVMS, Metrowerks.

thanks,
hys

**Even if that statement is not 100% correct, or in some cases you can
completely disable SEH/C++ interaction via non-portable #pragma or
compile-flag, I can imagine a situation involving a special platform-native
private C++ exception type, _not_ inherited from std::exception, that is
inaccessible to user code and only the OS can catch it by name (eg, to
represent a fatal process error for an OS written with C++). User code would
only be able to interact with this special exception via catch(...), subject
to all the same problems described above.

--
Hillel Y. Sims
FactSet Research Systems
hsims AT factset.com

Francis Glassborow

unread,
Jul 16, 2002, 5:04:06 PM7/16/02
to
In article <3D326BB4...@web.de>, Alexander Terekhov
<tere...@web.de> writes
>

>Do you see the point? Or am I missing and/or misunderstanding
>something?

Yes, you have been twice asked what 'khm' stands for. The first time you
gave a link that does not appear to answer the question and this time
you have provide two screen fulls that still does not appear to answer
the question.

--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Will Dean

unread,
Jul 16, 2002, 5:11:07 PM7/16/02
to
Jim Hyslop wrote:

> You are presuming we aren't being careful.

Well, you did post an example (which was probably vastly simplified) of
where you've been missing an acc-vio in the debug build because it's been
falling into catch(...) and going unnoticed.

I think some people are wondering whether your debug build
couldn't/shouldn't do something as obvious in catch(...) as an access
violation would have done if it had been detected.

After all, besides the MS funny, there may be all sorts of other bugs
(including those in preceding catch statements) which would cause you to
unexpectedly find yourself in catch(...).

Are there lots of things legitimately (i.e. you'd expect to see them during
ordinary debug build runs) going through catch(...)? What are they?

Will

Jim Hyslop

unread,
Jul 17, 2002, 6:33:26 AM7/17/02
to
In article <XBNY8.48163$6r.15...@news4.srv.hcvlny.cv.net>,
use...@phatbasset.com says...

>
> "Jim Hyslop" <jhy...@ieee.org> wrote in message
> news:MPG.17995092a...@news1.on.sympatico.ca...
> > No, catch(...) is about catching a C++ exception.
>
> std::exception is the path to nirvana (and robust code).
:=)

[...]


> I have read (hopefully carefully
> enough) the standard and found nothing which explicitly requires anything
> caught by catch(...) to be only something raised by a C++ "throw"
> statement.**

Right at the beginning of clause 15: "A handler will be invoked only by
a throw-expression invoked in code executed in the handlers try block
or in functions called from the handlers try block." No throw, no
catch, and anything that causes a handler to be entered without an
explicit "throw" statement is non-conforming.

[moved the footnote up for continuity]

> **Even if that statement is not 100% correct, or in some cases you can
> completely disable SEH/C++ interaction via non-portable #pragma or
> compile-flag, I can imagine a situation involving a special platform-native
> private C++ exception type, _not_ inherited from std::exception, that is
> inaccessible to user code and only the OS can catch it by name (eg, to
> represent a fatal process error for an OS written with C++). User code would
> only be able to interact with this special exception via catch(...), subject
> to all the same problems described above.

I don't agree. From the OS's point of view, the C++ exception handling
scheme is simply another tool for me, the programmer, to handle errors
in my program - a glorified setjmp/longjmp, if you will (remember, this
is from the OS's perspective, not ours).

If the OS is raising an exception that is intended for the OS to catch,
then that exception handling mechanism should be completely independent
of any software error handling. My program should not in any way be able
to intercept exceptions generated by the OS, intended to be received by
the OS, no matter what I do.

> C++ language code
> cannot and should not attempt to intervene in OS-native non-C++ exceptions

So why does the OS force its exceptions into my C++ program?

> >MSVC allows [catch (...)] to
> > catch a hardware exception
>
> Exactly why we must all avoid it.

No, I'd say this is exactly why we should tell MS (via our community
liaison, Herb Sutter, perhaps - Herb, are you following this thread?) to
provide an easier way to distinguish SE from C++ exceptions, so I can
put in my code:

#ifdef _MSC_VER
catch (MSC::StructuredException &)
{
throw;
}
#endif

or even turn it off entirely by a command-line switch.

> > of course it threw an access violation - which was
> > promptly absorbed by the nearest "catch (...)" statement.
>
> A good example of why it is evil.

No, I'd say this is a good example of hijacking. To me, "catch (...)"
means "catch any C++ exceptions that my program throws" - because *that*
is what the standard *says* it should do.

> C++ exception-handling cannot correctly handle exceptions that cannot be
> caught by a C++-accessible name. If you need to handle non-C++
> platform-specific exceptions, then you must use a non-C++ platform-specific
> mechanism.

But I don't _want_ to catch them - my compiler is _forcing_ me to catch
them.

> > Are there any implementations besides MSVC that support structured
> > exceptions?
>
> Tru64 Unix, OpenVMS, Metrowerks.

Thanks. Of these implementations, do any of them allow you to catch the
exception by a specific type, or do you use (...) to catch them? In
other words, how difficult is it to differentiate between a C++
exception and a SE?

--
Jim

Jim Hyslop

unread,
Jul 17, 2002, 6:34:05 AM7/17/02
to
In article <3d33461c....@news.online.no>,
alf_p_s...@yahoo.no.invalid says...

> Q: John Hyslop: thanx for the clarification -- and I remember
> the MSVC particulars now -- but
John? That'd be my dad :=)

> (1) exactly how does one
> "easily" protect against such double destruction, and

Well, Dave Abrahams was the one who suggested it, but I would presume it
would be something along the lines of making sure you set any pointers
to null in the dtor (which you normally wouldn't need to do).

> (2) can
> one be sure that program state (e.g. the stack, internally
> registered SEH exception handlers, etc.) is Ok after that?

Sorry, there's been so much cross-discussion I've lost the, er, thread
of what you're referring to here. Could you elaborate a bit more?

--
Jim

Jim Hyslop

unread,
Jul 17, 2002, 6:35:42 AM7/17/02
to
In article <1026814478.7308.0...@news.demon.co.uk>,
ab...@industrial.demon.co.uk says...

> Jim Hyslop wrote:
>
> > You are presuming we aren't being careful.
>
> Well, you did post an example (which was probably vastly simplified)
Of course it was. I'm sure even the character Bob (from Herb Sutter's
and my column "Conversations") could have spotted something *that*
obvious :=)

> I think some people are wondering whether your debug build
> couldn't/shouldn't do something as obvious in catch(...) as an access
> violation would have done if it had been detected.

> After all, besides the MS funny, there may be all sorts of other bugs
> (including those in preceding catch statements) which would cause you to
> unexpectedly find yourself in catch(...).

Our unit tests are fairly comprehensive, and they weed out any (OK,
most) bugs that might execute a "throw" statement at inappropriate
times. Other than that and structured exceptions, I'm not sure I can
imagine a bug that might unexpectedly go to the catch-all handler - do
you have any specific examples?

> Are there lots of things legitimately (i.e. you'd expect to see them during
> ordinary debug build runs) going through catch(...)? What are they?

Yes, we use exceptions when unusual events occur. In many cases, the
code doesn't care exactly which type of exception was thrown, it just
tries something, and has a catch-all handler which just cleans up then
re-throws the exception. This is where it would be *really* useful to be
able to distinguish a C++ exception from a C exception (which I know you
can do by using the _set_se_handler function, but I haven't had time to
implement it - each thread has to call _set_se_handler).

Actually, there is one thing I *really* like about MS's structured
exceptions, and that's the "finally" clause - the code in that block
always executes, no matter which handler handled the exception, and no
matter whether the exception was completely handled or re-thrown. That,
I think, would be a useful feature for C++ to incorporate. I keep
meaning to add it to the "C++0x Wish List" thread in comp.std.c++ :-)

--
Jim

Hillel Y. Sims

unread,
Jul 17, 2002, 6:36:57 AM7/17/02
to
"Jim Hyslop" <jhy...@ieee.org> wrote in message
news:MPG.179d10fc8...@news1.on.sympatico.ca...

> In article <3D32A955...@web.de>, tere...@web.de says...
> > < no.it... replaced with c.p.t. ;-) >
> >
> > Jim Hyslop wrote:
> > > No, catch(...) is about catching a C++ exception.
> >
> > Again, catch(...) is about catching ALL exception [>>C<< exceptions,
> > aka SEH, *including*]. ;-)
> No. If we were discussing this in a Microsoft-specific forum, then I
> would agree with you. As far as I can tell, this discussion is taking
> place in forums that are platform-independent.

This behavior exists on Tru64 Unix and OpenVMS platforms too.

> Therefore any discussion
> about what a C++ statement means must be in the context of how it is
> defined in the standard, and discussion on any platform-specific
> extensions should be confined to footnotes.
>
> The standard says "a handler will be invoked only by a throw-exception
> invoked in code executed in the handler's try block...." That means a
> catch statement can only catch a C++ exception. Anything else is an
> extension.

I don't believe the SEH mechanism necessarily violates the standard. Even
though the API is not C++, could the mechanism itself not be implemented in
C++ in something like the following manner?

generic_os_private_header.hpp
---------

namespace GenericOS {
namespace Private {
class FatalException { ... };
// FatalException is a synchronous exception thrown in a user process
upon
// detection of a fatal error condition (such as an address-space
access-violation
// error, aka GPF or segfault). This exception type is intentionally NOT
inherited
// from std::exception, and its name is private to this OS-internal
header, so
// that it cannot be caught directly by name by any user code. It is
intended to
// immediately cause the terminate() function to be called, giving a
chance for a
// custom terminate-handler routine to be executed.
}
}

In the context of such an exception (a true process fatal OS exception, not
a C++ std::exception-derived exception which should not be arbitrarily
allowed to terminate a process), it would rarely ever be a good idea for a
process to swallow it -- as you saw yourself with your Windows GPF error
that is sometimes silently swallowed.

MyClass::~MyClass()
{
try {
.. some function that could cause be broken ..
}
catch (...) {} // don't want to terminate the process! (?!)
}

Fortunately, the solution is easy, and we can achieve both robust software
that does not terminate upon spurious throw of C++ exception, but that does
not inadvertently trap OS fatal errors. By following the rule of inheriting
all user-defined exceptions from std::exception and catching blanket
exceptions via catch (std::exception&), your software will be much stronger.

>
> > > MSVC allows it to catch a hardware exception - and this has cost us
> > > no end of grief,
> >
> > There are many-many other exceptions that could "cost us no end of
> > grief" if propagated/caught blindly.
> In the environment I'm working in (see below) the cost of allowing an
> exception to go unhandled vastly outweighs whatever it would cost to
> "blindly" catch an exception.

"catch (...) {}" is likely not a good method of handling fatal process
exceptions. You already provided a real-world example of insidious behavior
caused by catch (...). The better solution than trying to find a
platform-specific workaround (and then your code will still be broken on
other platforms that do not have the same workaround) is via the
std::exception route. catch(std::exception&) can catch all (non-fatal)
exceptions without the possibility of interfering with OS-based fatal
exceptions. Simply inherit all custom-defined exceptions from
std::exception, and do not throw any other types (avoid int or char*
exceptions).

>
> But until this integration happens, non-C++ exceptions are non-standard
> and therefore non-portable. MS should IMO provide a better, easier way
> to disable non-C++ exceptions.

Tru64 Unix and OpenVMS are some non-MS platforms that experience the same
issues. It is not just an MS-specific issue. The better solution is for all
programmers to only use true named C++ exception types, all derived from
std::exception for a common base class, and then completely avoid the issue
entirely.

> The company I work for produces television broadcast equipment. We
> supply equipment to most of the major networks around the world. If you
> watched any of the World Cup on TV, the signal you watched passed
> through our equipment, some of it at the control room in Korea. Now, if
> our equipment suddenly barfed and rebooted at a critical moment because
> of an unhandled exception, the CEOs of these aforesaid major networks
> would be screaming at my CEO, who would promptly come around handing out
> pink slips.

Unhandled C++ exceptions should not cause spurious termination of user
processes. Non-C++ exceptions cannot and should not be handled in C++ code
(via catch(...)). If you must handle conditions such as access-violation,
then you must necessarily fall back to platform-specific APIs. If you wish
to remove such heinous bugs as "GPF in debug mode, not in release mode",
avoid catch (...) and use the std::exception pattern.

- Inherit all of your custom exceptions from std::exception (all C++ library
exceptions already follow this rule). Do not throw int or char*.
- catch all exceptions via catch (std::exception&).
- specifically handle OS-specific non-C++ exceptions via OS-specific non-C++
mechanism (only).

>
> But the software *can* - and in our case must - do something about
> catching exceptions. All of them.

C++ should only be concerned about catching C++ exceptions. All other
non-C++ exceptions should be handled by OS-specific code. By using the
std::exception hierarchy for all C++ exceptions, it is always trivial to
distinguish between these.

thanks,
hys

--
Hillel Y. Sims
FactSet Research Systems
hsims AT factset.com

David Abrahams

unread,
Jul 17, 2002, 6:38:19 AM7/17/02
to

"Hillel Y. Sims" <use...@phatbasset.com> wrote in message
news:XBNY8.48163$6r.15...@news4.srv.hcvlny.cv.net...

>
> "Jim Hyslop" <jhy...@ieee.org> wrote in message
> news:MPG.17995092a...@news1.on.sympatico.ca...
> > No, catch(...) is about catching a C++ exception.
>
> std::exception is the path to nirvana (and robust code).
>
> 1) Never use catch(...), especially in portable code.

How would you write uninitialized_fill without catch(...)?

> 2) Always derive all custom exception-types from std::exception (or
> subclass), without exception.
> 3) Catch all C++ exceptions (where necessary) via catch (std::exception&),
> which is guaranteed to work if rule 2 is followed.

Yeah, but if you're interfacing with other peoples' libraries, or writing
templates, or writing frameworks that supply base classes with virtual
functions, you don't always have control over the types of exceptions that
get thrown. Writing certain kinds of exception-neutral code efficiently can
be extremely difficult without catch(...).

> catch (std::exception&) is all about catching all C++ exceptions. catch
> (...) is specifically about catching anything the platform might possibly
> throw at you (such as access violation) that lives on the same native
> runtime mechanism on which C++ exception-handling is implemented, without
> any knowledge of its context or type. I have read (hopefully carefully
> enough) the standard and found nothing which explicitly requires anything
> caught by catch(...) to be only something raised by a C++ "throw"
> statement.**

Well, that's true. On platforms which do something else, it's an extension.
It's an extension in the same sense that the standard gives libraries
permission to supply a zerovectors() function which sets the length of all
std::vectors in your program to zero. I don't think that's a reason to avoid
using std::vector, though it might be a good reason to avoid using
zerovectors().

> All this makes it legal for platforms (eg Windows, Tru64 Unix,
> OpenVMS) to implement their C++ runtime conveniently on top of the
> OS-native SEH exception mechanism, with the result that all SEH exceptions
> can be caught in catch(...) blocks. This makes it actually very
deceptively
> dangerous to use catch(...) as an attempt at achieving nothrow status
(such
> as in dtors)

It would almost never be a good idea to do that anyway, even in the absence
of some kind of "OS-native SEH exception mechanism".

> or for error protection, because that block is likely to be
> executed not just upon throw of a C++ exception, but also upon a fatal
> corruption of the program state (such as access violation) which is raised
> as an SEH exception.

The cure for that is "don't corrupt the program state". If it's fatal anyway
it doesn't matter (except from a debugging POV -- any system which takes
unwinding actions before I get to inspect the program state on a crash just
has poor QOI).

> This means it is unknowingly possible that it is
> already far too late for any attempt at nothrow or error protection.
(Error
> correction of that sort of error, if any, must happen explicitly via
> platform-specific API code, and should not be attempted by ordinary
generic
> user code.) Even in a nothrow block, capturing a non-C++ fatal process
> exception and continuing normal execution after that point as if nothing
bad
> actually happened is virtually always a Very Bad Thing

That's virtually always a Very Bad Thing even with a regular C++ exception.

> (especially if you
> try to write out some important data somewhere which is possibly
unknowingly
> corrupted...).
>
> There is a simple way to write correct nothrow code that does not suffer
> from this problem. _All_ C++ exceptions (including custom-defined types of
> even minimal complexity) must always be inherited from std::exception (or
> subclass).

This is misguided. If your nothrow functions are full of catch(xxx) {}
blocks which are designed to absorb all problems, you're doing something
wrong -- no matter whether you spell xxx "..." or "std::exception&". Nearly
every nothrow function is nothrow by virtue of inductive reasoning: it
doesn't call anything which can throw. The very few exceptions to this rule
can be thought of as "try to do yyyy if possible, but it doesn't really
matter whether it works".

> Non-std::exception-derived objects (such as int, or char*) should
> simply never be thrown.

Probably true, because the type is simply not descriptive enough.

> It is just a bad idea to throw any kind of exception
> object other than something derived from std::exception.

This kind of absolutism is bad for thinking programmers.

> The ultimate base
> class of any custom exception hierarchies should always inherit from
> std::exception. If you have a third-party library that uses exception
> objects that are not derived from std::exception which you cannot correct,
> then you're out of luck; you would need to additionally explicitly use
> "catch (library::base_exc&)" in all instances to catch those exceptions.
> Substitution of catch(...) is not a suitable strategy, as it opens the
door
> to receive non-C++ exceptions.

From the POV of the standard, there're no such things as "non-C++
exceptions", and many platforms don't have such a beast. Anyway, what do you
think the behavior should be if your program's running along happily and a
"non-C++ exception" passes through it?

> Always derive all exception objects from std::exception (or subclass),
> without exception. This is the only way to correctly catch all C++
> exceptions in one statement without interfering with OS-specific non-C++
> mechanisms.
>
> By following this simple and straightforward convention, it makes it
> possible in all cases to correctly catch _all_ (and ONLY) C++ exceptions
via
> one blanket statement (of course, even this is not necessarily completely
> safe all the time, but sometimes it is necessary...). C++ language code
> cannot and should not attempt to intervene in OS-native non-C++ exceptions
> under the vast majority of circumstances, and especially not inadvertent
> circumstances (even to try to do cleanup), as it has no inherent knowledge
> of OS-native implementation and context.

Well, what *should* happen? If your C++ program's not going to catch these
alien things, aren't they going to terminate your program anyway? In that
case, wouldn't it be better to install hooks which call dumpcore() or the
equivalent right where the things are getting thrown?

> Observance of the std::exception-or-bust rule provides an easy way to
avoid
> any need for or ill concerns resulting from use of catch(...).
>
> >MSVC allows [catch (...)] to
> > catch a hardware exception
>
> Exactly why we must all avoid it.

Not all of us need to be constrained by the brokenness of MSVC. They're
going to fix that eventually. In the meantime I'm willing to use my
_set_se_handler() hack and to trust that the very small quantity of code I
have in catch() blocks is not crashing in a way that I need to recover the
exact program state for debugging purposes.

> [..]
> > of course it threw an access violation - which was
> > promptly absorbed by the nearest "catch (...)" statement.
>
> A good example of why it is evil.

The evil here is a poor implementation choice which intertwined what should
have been a simple resumption model mechanism for handling OS traps with the
clean C++ exception implementation.

> C++ exception-handling cannot correctly handle exceptions that cannot be
> caught by a C++-accessible name. If you need to handle non-C++
> platform-specific exceptions, then you must use a non-C++
platform-specific
> mechanism. This can indeed make it (very much) more difficult to write
> robust C++ code for use on environments that do not fully integrate their
> native error-handling mechanisms with the C++ exception-handling
mechanism.

Au contraire, those environments are part of the problem. Full separation of
resumption-model for hardware faults and undefined behavior from termination
model for language-level exceptions is what's needed.

> However, as clearly displayed by your problem above, catch(...) is
certainly
> not the path to achieving robust high-availability code.

On that we are in agreement. However, catch(std::exception&) is no magic
bullet either.

> > Are there any implementations besides MSVC that support structured
> > exceptions?
>
> Tru64 Unix, OpenVMS, Metrowerks.

The first 2 are platforms; the third is a collection of implementations of
which only one supports SEH to my knowledge.

> **Even if that statement is not 100% correct, or in some cases you can
> completely disable SEH/C++ interaction via non-portable #pragma or
> compile-flag, I can imagine a situation involving a special
platform-native
> private C++ exception type, _not_ inherited from std::exception, that is
> inaccessible to user code and only the OS can catch it by name (eg, to
> represent a fatal process error for an OS written with C++). User code
would
> only be able to interact with this special exception via catch(...),
subject
> to all the same problems described above.

It's possible to imagine all kinds of legal language/library extensions
which, if used, would undermine the robustness of any given language
feature. Trying to pick which language features to use based on ways we can
imagine them being undermined is a dangerous kind of FUD for anyone with a
creative mind.

-Dave

Alexander Terekhov

unread,
Jul 18, 2002, 10:40:19 AM7/18/02
to

Francis Glassborow wrote:
>
> In article <3D326BB4...@web.de>, Alexander Terekhov
> <tere...@web.de> writes
> >
> >Do you see the point? Or am I missing and/or misunderstanding
> >something?
>
> Yes, you have been twice asked what 'khm' stands for. The first time you
> gave a link that does not appear to answer the question and this time
> you have provide two screen fulls that still does not appear to answer
> the question.

Okay, I'll try one more time (see some comp.std.c++ archive for the full
context -- Subject: Re: throw() can be good for optimization):


Francis Glassborow wrote:
[...]
> An empty throw spec. is just an ES and is treated the same way as all
> others (we try to avoid special casing things). While it is true that
> the unexpected_handler cannot do anything to allow the process to
> continue because it cannot replace the exception with another, in
> general (other than for empty throw specs) this is possible and the
> rules (reasonably IMO) state that such a catch is effectively handling
> the original exception.

What "such catch"? I am talking about stack-unwinding
PRIOR to unexpected()/terminate() invocation and "problems"
(as it seems to me) resulting due to this behavior, for
example:

<snip the link to "khm" example>

> The design may not be ideal but to describe it as emphatically seriously
> broken is a serious over-statement.

Yeah, e.g. if/when you just can't debug/analyze problems
(abends) once you ship your programs to customer (without
full recreation data/..., if its possible/deterministic
at all/enough), that's just "may not be ideal", and of
course, "broken is a serious over-statement", right! ;-)

regards,
alexander.

Alexander Terekhov

unread,
Jul 18, 2002, 10:43:09 AM7/18/02
to

"Hillel Y. Sims" wrote:
>
> "Jim Hyslop" <jhy...@ieee.org> wrote in message
> news:MPG.17995092a...@news1.on.sympatico.ca...
> > No, catch(...) is about catching a C++ exception.
>
> std::exception is the path to nirvana (and robust code).

No.

> 1) Never use catch(...), especially in portable code.
> 2) Always derive all custom exception-types from std::exception (or
> subclass), without exception.
> 3) Catch all C++ exceptions (where necessary) via catch (std::exception&),
> which is guaranteed to work if rule 2 is followed.

Hillel, I'm sorry for being a bit sort-of too-"persistent",
but I'm still awaiting your reply to the following comp.std.c++
article of mine:

http://groups.google.com/groups?selm=3C7DEFBB.C48B0694%40web.de
< uhmm, id: 3-C-7-D-E-F-B-B-.-C-4-8-B-0-6-9-4-%-4-0-w-e-b-.-d-e >

"Hillel Y. Sims" wrote:
[...]
> Few people seem to be aware of this issue (or at least discuss it much
> publicly), but many of us program in a multi-threaded world. For example,
> following the typical exception-safety conventions recommended by
> Meyers/Sutter/etc. for protecting nothrow code via try {...} catch (...) {}
> as necessary is not completely valid when thread-cancellation exceptions are
> used; it is inappropriate to catch and swallow a thread-cancellation
> exception. Thread-cancellation must be disabled in these regions in order
> for the catch (...) {} to be correct. (Actually, it should probably even be
> catch (std::exception&) {} because you don't really want to catch any
> unknown exceptions such as accvio...)

You don't really want to catch&ignore any of these:

logic_error
domain_error
invalid_argument
length_error
out_of_range
runtime_error
range_error
overflow_error
underflow_error

*known* exceptions TOO (and anything else) IF they
were thrown *UNEXPECTEDLY*. Gee! Why not just terminate
the whole process, leaving that nice dump-info for the
friendly service/change team and try to recover/retry
in a NEW/CLEAN address space from the persistent (non-/
less-volatile storage) program-state info saved (e.g.
incrementally updateable objects store, home grown) at
the last GOOD (as it appeared and most likely *truly*
good) CHECK POINT!? Just consider/treat it as the
unexpected power-off/loss situation. "Good" programs
SHOULD deal with this too, IMHO! ;-)

> This makes it difficult to write
> portable code, since it cannot be correct without CancelGuard on
> multi-threaded systems. It would definitely be nice if the whole issue could
> be more smoothly integrated into the language

Yup. Something along the lines of:

- async-cancel-safety enforced by the compiler;
- bool expected_exception<T>();
- bool unwinding(T*);
- something to code LOCAL context templates/objects
that would have the same local access/visibility
as Java's "finally" clauses do;
- thread-safe static locals for IMMUTABLE lazy
singeltons;
- transition of <pthread.h> into <cthread>;
- some decent <thread> C++ "wrappers" that would
basically do the same as <cthread> stuff, BUT
in MORE EXPRESSIVE/LESS ERROR-PRONE (get rid
of "detach", etc) way then the current C-style
threaded programming.

...and, of course, post-/pre- c/d-tors! ;-)

regards,
alexander.

David Abrahams

unread,
Jul 18, 2002, 10:49:14 AM7/18/02
to

"Jim Hyslop" <jhy...@ieee.org> wrote in message
news:MPG.179ea5a57...@news1.on.sympatico.ca...

> > (1) exactly how does one
> > "easily" protect against such double destruction, and
> Well, Dave Abrahams was the one who suggested it, but I would presume it
> would be something along the lines of making sure you set any pointers
> to null in the dtor (which you normally wouldn't need to do).

That's right.

-Dave

Alf P. Steinbach

unread,
Jul 18, 2002, 10:56:52 AM7/18/02
to
On 17 Jul 2002 06:34:05 -0400, jhy...@ieee.org (Jim Hyslop) wrote:

>In article <3d33461c....@news.online.no>,
>alf_p_s...@yahoo.no.invalid says...
> > Q: John Hyslop: thanx for the clarification -- and I remember
> > the MSVC particulars now -- but
>John? That'd be my dad :=)

Sorry, I wrote that late at night; I found the earlier parts of the
thread in Google archives.

>
> > (1) exactly how does one
> > "easily" protect against such double destruction, and
>Well, Dave Abrahams was the one who suggested it, but I would presume it
>would be something along the lines of making sure you set any pointers
>to null in the dtor (which you normally wouldn't need to do).
>
> > (2) can
> > one be sure that program state (e.g. the stack, internally
> > registered SEH exception handlers, etc.) is Ok after that?
>Sorry, there's been so much cross-discussion I've lost the, er, thread
>of what you're referring to here. Could you elaborate a bit more?

Both problems refer to an automatic compiler-generated double
destruction in the case of an internal catch-clause rethrow-and-catch,
where one doesn't have control over which exception is destroyed --
much of the point of the construction is to catch & convert
non-standard exceptions from library code such as Lotus Notes and
MFC. Off the cuff (not actual code):

void convertException()
{
try{
throw;
} catch( TypeA const& x ) {
throw MyStdException( x );
} catch( TypeB const& x ) {
throw MyStdException( x );
} /* etc. */ {
} catch( MyStdException const& x ) {
throw;
} catch( std::exception const& x ) {
throw MyStdException( x );
} catch( ... ) {
throw MyStdException( "Unknown inner exception" );
}
}

// Somewhere, anywhere:
try{
someOperationThatMayThrowSomeNonStandardException();
} catch( ... ) {
convertException();
}

So one doesn't really have the option to do much about the
internal exception cleanup... That's why I didn't understand
how to easily guard against the MSVC (and possibly other
compilers') double exception destruction. Dave?

Main question is also still there: does this generally work
on other compilers (i.e., are they now standard-compliant)?

Cheers,

- Alf

Andrea Griffini

unread,
Jul 18, 2002, 10:58:47 AM7/18/02
to
On 17 Jul 2002 06:33:26 -0400, jhy...@ieee.org (Jim Hyslop) wrote:

>No, I'd say this is a good example of hijacking. To me, "catch (...)"
>means "catch any C++ exceptions that my program throws" - because *that*
>is what the standard *says* it should do.

I stepped today on that VC++ problem too. Code written by a
collegue was behaving very strangely. It turned out he used
catch(...) adsorbing the exception in a DLL. The exception are
used inside the DLL but catch(...) intercepted also memory
faults hiding errors in a strange way.

After some thinking I've come to the conclusion that catch(...)
is good only if you are going to terminate the program (may be
after some last desperate tentative to save something - but I'm
not sure if I like that) as adsorbing an unknown event doesn't
describe what I call a robust program... it's just code that
*hide* errors and that cripple my documents instead of dying
immediately as it should. To not make me waste last hour on
my WP doc it make me waste last *month* crippling its internal
structure with a bad save that I'll discover only after a
long time (just after all backups got a corrupted version,
Murphy says).

I think however that MS is not violating anything doing that...
writing out of an array is Undefined Behaviour and performing
a stack unwinding until it gets to a catch(...) is something
that may happen once you enter the dark territories of UB.

So using catch(...) to adsorb an exception is in my opinion a
"don't", but I think MS did a good thing with current behaviour
instead of formatting my hard disk (UB may mean that too).

If your program got to a catch(...) and that is not because
of one of your throws then you already violated the rules,
so I wouldn't complain ... you were anyway just going to
kill your program immediately with a loud yell, right ?


Andrea

Alexander Terekhov

unread,
Jul 18, 2002, 11:35:21 AM7/18/02
to

David Abrahams wrote:
[...]

> How would you write uninitialized_fill without catch(...)?

Show me the code, please.

[...]


> Yeah, but if you're interfacing with other peoples' libraries, or writing
> templates, or writing frameworks that supply base classes with virtual
> functions, you don't always have control over the types of exceptions that
> get thrown. Writing certain kinds of exception-neutral code efficiently can
> be extremely difficult without catch(...).

Examples?

[...]


> The cure for that is "don't corrupt the program state". If it's fatal anyway
> it doesn't matter (except from a debugging POV

No, not only "except from a debugging POV".

> -- any system which takes
> unwinding actions before I get to inspect the program state on a crash just
> has poor QOI).

Okay, but what is this, then:

"The fields unexpectedHandler and terminateHandler contain
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pointers to the unexpected and terminate handlers at the
point where the exception is thrown.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The ISO C++....(18.6.2.4) states that the handlers to be
used are those active immediately after evaluating the
throw argument. If destructors....not used
until unwinding is complete."
^^^^^^^^^^^^^^^^^^^^^^^^^^^

To me, that's nothing but poor SOMETHING in the current
C++ standard. Please-please, fix it, please.

[...]


> From the POV of the standard, there're no such things as "non-C++
> exceptions", and many platforms don't have such a beast. Anyway, what do you
> think the behavior should be if your program's running along happily and a
> "non-C++ exception" passes through it?

Consider [somewhere in the "threads/C/C++ related" DEC->Compaq->HP docu]:

"You can use the C language exception handling mechanism (SEH) to catch
exceptions. You can catch exceptions in C++ using catch(...), and propagation
of exceptions will run C++ object destructors. Currently, C++ code cannot
catch specific exceptions. .... ^^^^^^^^^
(These restrictions will be reduced or removed in a future release.)"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> It's possible to imagine all kinds of legal language/library extensions
> which, if used, would undermine the robustness of any given language
> feature.

The robustness of the standard C++ exceptions "feature" is /already/
and _/totally/_ undermined by a) implementation-defined unwinding for
uncaught exceptions [debugging is a /secondary/ issue here, really]
and b) *required unwinding* on violations of ex. specs; IOW, NOT by
something like SEH extensions, IMO.

regards,
alexander.

Alexander Terekhov

unread,
Jul 18, 2002, 11:35:57 AM7/18/02
to

Matthew Collett wrote:
[...]

> Not if your RAII is doing its job. Unwinding the stack as you leave
> c() will call the RAII object's destructor, which should reset the
> unexpected handler to whatever it was before entering c(). The
> implicit catch(...) in a() that actually _calls_ the unexpected
> handler isn't reached until after this resetting has occurred, so
> all should be well.
>
> > Or am I missing and/or misunderstanding something?
>
> Or maybe I am ...

Somewhat vague standard-bits aside [you might want to check out
the posts from Mr. Lancaster (in the comp.std.c++ thread I've
referenced earlier) attempting to interpret it... and I agree
with his interpretation], consider:

http://www.codesourcery.com/cxx-abi/abi-eh.html

"....
2.1 C++ Exception Objects

A complete C++ exception object consists of a header,
which is a wrapper around an unwind object header with
additional C++ specific information, followed by the
thrown C++ exception object itself. The structure of
the header is as follows:

struct __cxa_exception {
std::type_info * exceptionType;
void (*exceptionDestructor) (void *);
unexpected_handler unexpectedHandler;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
terminate_handler terminateHandler;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
....


The fields unexpectedHandler and terminateHandler contain

pointers to the unexpected and terminate handlers at the

point where the exception is thrown. The ISO C++ Final
Draft International Standard [lib.unexpected] (18.6.2.4)


states that the handlers to be used are those active
immediately after evaluating the throw argument. If

destructors change the active handlers during unwinding,
the new values are not used until unwinding is complete."
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

regards,
alexander.

Doug Harrison

unread,
Jul 18, 2002, 2:57:12 PM7/18/02
to
Hillel Y. Sims wrote:

>catch (std::exception&) is all about catching all C++ exceptions. catch
>(...) is specifically about catching anything the platform might possibly
>throw at you (such as access violation) that lives on the same native
>runtime mechanism on which C++ exception-handling is implemented, without
>any knowledge of its context or type.

People often think that's a good idea. Here are some sample messages
explaining why I completely disagree with them:

http://groups.google.com/groups?selm=eW%23ZKH8P%23GA...@uppssnewspub05.moswest.msn.net
http://groups.google.com/groups?selm=k9etqs855giltd5se...@4ax.com

FWIW, I've been arguing this point for eight years, and I've never
heard a reasonable argument why catch(...) should catch untranslated
Win32 structured exceptions.

--
Doug Harrison
d...@mvps.org

Matthew Collett

unread,
Jul 19, 2002, 6:05:24 AM7/19/02
to
In article <3D3547BE...@web.de>,
Alexander Terekhov <tere...@web.de> wrote:

> The ISO C++ Final
> Draft International Standard [lib.unexpected] (18.6.2.4)
> states that the handlers to be used are those active
> immediately after evaluating the throw argument. If
> destructors change the active handlers during unwinding,
> the new values are not used until unwinding is complete."
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>

> alexander.

Arrgh! Now I understand why you are unhappy about this. This goes
against everything I'd understood about the way exceptions worked.
I thought the whole point was that the stack was supposed to unwind
cleanly and _completely_.

Yet another reason never to bother with exception specifications, I
suppose.

Best wishes,
Matthew Collett

--
The word "reality" is generally used with the intention of evoking sentiment.
-- Arthur Eddington

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

David Abrahams

unread,
Jul 19, 2002, 6:33:20 AM7/19/02
to

"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
news:3d359f82...@news.online.no...

> So one doesn't really have the option to do much about the
> internal exception cleanup... That's why I didn't understand
> how to easily guard against the MSVC (and possibly other
> compilers')

This is an MSVC-specific bug which I've never seen elsewhere. Vague
implications to the contrary are just FUD-fodder.

> double exception destruction. Dave?

You can't fix the compiler. I said to work around it you need to exercise
care in the design of your exception classes.

If you have data with a non-trivial destructor in your exception object,
hold it by-pointer. When the pointer gets deleted in the destructor, make
sure you set it to 0 so that another deletion is innocuous. Or, you can use
auto_ptr<>s or boost::shared_ptr<>s and reset() them in the exception's
destructor.

> Main question is also still there: does this generally work
> on other compilers

Generally, yes.

(i.e., are they now standard-compliant)?

That's a different question. Generally, no (c.f. export).

-Dave

Hillel Y. Sims

unread,
Jul 19, 2002, 8:36:17 AM7/19/02
to

"Doug Harrison" <d...@mvps.org> wrote in message
news:lihcjus48p7c5vvle...@4ax.com...

> Hillel Y. Sims wrote:
>
> >catch (std::exception&) is all about catching all C++ exceptions. catch
> >(...) is specifically about catching anything the platform might possibly
> >throw at you (such as access violation) that lives on the same native
> >runtime mechanism on which C++ exception-handling is implemented, without
> >any knowledge of its context or type.
>
> People often think that's a good idea. Here are some sample messages
> explaining why I completely disagree with them:
>
>
http://groups.google.com/groups?selm=eW%23ZKH8P%23GA...@uppssnewspub05.mosw
est.msn.net
>
http://groups.google.com/groups?selm=k9etqs855giltd5seolk6pv8ssnj2k7p6l@4ax.

com
>
> FWIW, I've been arguing this point for eight years, and I've never
> heard a reasonable argument why catch(...) should catch untranslated
> Win32 structured exceptions.
>

I totally agree with you in principle. _However_, from a realistic/pragmatic
point of view, this behavior exists and is the default behavior on many
platforms, and is frankly unlikely to change anytime in the near future (and
it is NOT just Windows, it's also an issue on Tru64 and OpenVMS and possibly
others, which interests me personally since I do most of my development on
VMS). AND in fact, there is NO workaround for it on VMS (maybe on Windows
you have a workaround; even if it is fully reliable, I wonder about the
relative merits of a platform-specific workaround vs. the always-correct
fully-portable alternative of std::exception-derived exceptions)

If every bit of your code ONLY throws and catch exceptions inherited from
std::exception, then by inductive reasoning you never need to worry about
catch(...) (even from generic templated code) and you never need to worry
about intercepting OS exceptions regardless of the platform. I won't go
quite so far as to say it's a mistake in C++ that you can throw exceptions
other than inherited from std::exception, but I will strongly suggest it is
very poor form for programmers to do so (and I do note that all std library
exceptions inherit from std::exception). Please, anyone, show me one aspect,
minor or major, whereby there is any downside to inheriting all your
exception objects from std::exception (other than having to type a few extra
characters to define the object..)?

As far as other aspects of catch(...), let me just try to make a couple of
points that will hopefully cover all the issues:

1) The "catch(...) { throw; }" rethrow idiom -- IF you _always_ _rethrow_
the UNALTERED exception from a catch(...) block (and it is fairly
unconscionable to swallow it / "translate" it... so far Jim Hyslop and
Andrea Griffini have posted examples of the evil that happens when you
swallow unknown exceptions; and you can't legitimately try to translate it
either -- how can you even try to translate something that you can't even
possibly know what it is???) -- if you rethrow the exception, this is not AS
bad as swallowing it. However, there are _still_ two undesirable side
effects from result even this seemingly harmless _forced_ unwinding:
- high importance: if you are unwinding during a hardware exception, you
may end up corrupting persistent extra-process state (eg. disk files,
network, etc). Since the fact that a hardware exception has been raised
indicates that there is unknown corruption in your program state, any
unwinding at all in this state is usually a bad idea. Much better to rely on
automatic object (have you tried Alexandrescu/Marginen's ScopeGuard package?
ON_BLOCK_EXIT is a safe 99%-"finally" for C++! It's fabulous!!) /
std::exception-only unwinding, in which case you can usually avoid forced
unwinding due to a fatal program state corruption problem (assuming your
platform doesn't force it on you, but that's clearly an aspect of QoI; at
least VMS doesn't force it unless there is catch(...)). (and yes, you can
also avoid this problem by not corrupting your program state in the first
place, ha ha..)

This is one objection to even using the "catch(...) { throw; }" form -
it can cause unintended permanent data corruption.

- moderate importance: it can interfere with post-crash debugging. At
least on VMS, the stack traceback / core dump mechanism which is triggered
when an exception causes a program to terminate can only snapshot the
deepest level of the call stack which is still available when the exception
propagates outside of main(). If a catch(...) is encountered along the way,
the entire portion of the call stack deeper than that is unwound and cleaned
up before the exception is rethrown, and important debugging context is
permanently lost. When the exception finally propagates outside main() and
causes the abnormal termination / stack trace / core dump, the call stack no
longer shows any meaningful information past the last catch(...) block which
was encountered.

Well I'm sure that some people may think "QoI!" about this point. But
please consider again that this is the reality behind some OSs, and the
ability to avoid catch(...) completely through use of std::exception-derived
exceptions removes this entire issue from the table without having to worry
about if/when a vendor is going to fix their OS or if there are
platform-specific hooks to trap fatal errors and in the meantime we're stuck
scratching our heads wondering why std::vector constructor's catch(...)
block shows up as the last thing on the call stack and what could have
possibly actually triggered the exception in the user-defined type?


2) The "catch(...) {}" form -- often propounded (NOT by me, thank you) as a
way to make destructors nothrow safe. Of course you typically determine
nothrow status by inductive reasoning, and typically you do _not_ wrap your
destructors in try { ... } catch (xxx) {} blocks of any nature (_I_ am _not_
suggesting this as general good practice), _however_ please consider a
destructor in a high-reliability fault-tolerant application which must call
a cleanup function in an external DLL. You, as the programmer of this object
, may be legitimately concerned that that function could throw an exception,
and that would be a Bad Thing to allow to propagate outside your destructor.
Thus, the advice commonly encountered in various print media by major
authors and other outlets would be to do something like the following:
Obj::~Obj()
{
try {
dll_cleanup_function_that_does_zeus_knows_what();
}
catch (...) {}
}

Can we all agree that this is Very Bad in the presence of hardware
exceptions that may come through the catch(...)? (I am not claiming that
those who have suggested that idiom were somehow "dumb" or did not know what
they were talking about -- rather this seems to be a somewhat under-explored
area and is not even an issue at all on most unix boxes which many people
are familiar with, so I can understand why this advice may have been given
in seemingly good conscience in the past, but I do feel it is somewhat
misguided in light of the hardware exception issue.)

Now, if your application-level exception objects are being thrown
willy-nilly inherited from any random hierarchy or even ints and char*s, or
you are writing templated code, then you probably sort of feel like you have
no choice, because the alternative is that your application may terminate
randomly due to unhandled exception. Well let me just say that if this is
the case, the catch (...) {} form is NOT safely portable and is absolutely
no safer, and will at most give a false sense of security, because now your
application may randomly NOT terminate when it really should have (and now
your elevator software that should have triggered an automatic system reboot
upon fatal exception will continue to run with a faulty program state and
maybe decide to just accelerate downward at maximum speed from the top floor
with a full load of passengers...).

The only really safe and portable alternative is to rely on the inductive
reasoning available whereby all application exceptions are inherited from
std::exception. If this is the case, then it is both legal and safe and
fully robust to use "catch (std::exception&) {}" as the maximum-strength
"cannot let any exceptions propagate" form of exception handling, and you
can allow hardware faults / OS exceptions to propagate and be handled by
their own appropriate mechanism (for which I think we all agree at this
point that C++ catch is not appropriate).


To sum up, I agree in principle with those who believe in total separation
of hardware and software exceptions. However, from a pragmatic viewpoint,
the separation is not complete and is not something that can easily be
escaped, but it can be easily achieved by only using exceptions that are
inherited from std::exception. This provides the logical basis for being
able to effectively do a catch-all-C++-exceptions when necessary without
having to worry about the negative side-effects of catch(...).

I suggest that using/throwing any exceptions not inherited from
std::exception is at best very poor/lazy form in almost all cases, except
maybe some very special/rare circumstances where you would have to have a
very good reason for doing so (so as to avoid corrupting the whole logical
basis of the catch(std::exception&) as catch-all-C++-exceptions). I suggest
it is virtually always inappropriate to use catch(...), substituting
catch(std::exception&) instead in those circumstances when it is absolutely
necessary. (Maybe this would even encourage more people to inherit their
exceptions from std::exception since they will see that ... will not "save"
them.)

Any programmer who wishes to use C++ exceptions really should have a good
understanding of this interaction, that exists and is probably not going
away anytime soon, and how to safely work with it, or they will actually end
up with less-robust software than they would have had had they continued to
use the old non-exception style of programming. If you are on various unix
boxen, then you apparently don't even need to consider this issue at all,
and if you're on Windows, then you apparently have a platform-specific
workaround available, so good luck with that (assuming it is 100% reliable),
but PLEASE consider that there are not always reliable platform-specific
workarounds and that the simple act of always inheriting your exceptions
from std::exception does provide a fully-portable and completely robust
basis for automatic and absolute separation of all hardware/software
exception interaction concerns.

thanks,
hys

--
Hillel Y. Sims
FactSet Research Systems
hsims AT factset.com

Alf P. Steinbach

unread,
Jul 20, 2002, 6:09:09 AM7/20/02
to
On 19 Jul 2002 06:33:20 -0400, "David Abrahams"
<david.a...@rcn.com> wrote:

>
>"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
>news:3d359f82...@news.online.no...
>
> > So one doesn't really have the option to do much about the
> > internal exception cleanup... That's why I didn't understand
> > how to easily guard against the MSVC (and possibly other
> > compilers')
>
>This is an MSVC-specific bug which I've never seen elsewhere. Vague
>implications to the contrary are just FUD-fodder.

I had to look up what "FUD" means, found an explanation at
[http://www.geocities.com/SiliconValley/Hills/9267/fuddef.html].

Hm. I do read some journals and haven't seen any such tactics
lately, or indeed in many years, regarding C++ compilers. Perhaps
you could provide an example? (E.g. in a new thread.)


>
> > double exception destruction. Dave?
>
>You can't fix the compiler. I said to work around it you need to exercise
>care in the design of your exception classes.
>
>If you have data with a non-trivial destructor in your exception object,
>hold it by-pointer. When the pointer gets deleted in the destructor, make
>sure you set it to 0 so that another deletion is innocuous. Or, you can use
>auto_ptr<>s or boost::shared_ptr<>s and reset() them in the exception's
>destructor.

Thanks, but since this won't work with exceptions outside one's
control the conclusion seems to be that:

the technique can't be (generally) used with the MSVC compiler,
i.e. for Windows programming, but is supported by both the
standard and actual compilers on other platforms.


>
> > Main question is also still there: does this generally work
> > on other compilers
>
>Generally, yes.
>
>(i.e., are they now standard-compliant)?
>
>That's a different question. Generally, no (c.f. export).

Sad to hear that. Perhaps a redesign of "export" should be
considered for the next version of the standard?

Cheers,

- Alf

Alan Griffiths

unread,
Jul 20, 2002, 6:25:29 AM7/20/02
to
agr...@tin.it (Andrea Griffini) wrote in message news:<3d35ab3...@news.tin.it>...

> On 17 Jul 2002 06:33:26 -0400, jhy...@ieee.org (Jim Hyslop) wrote:
>
> >No, I'd say this is a good example of hijacking. To me, "catch (...)"
> >means "catch any C++ exceptions that my program throws" - because *that*
> >is what the standard *says* it should do.
>
> I stepped today on that VC++ problem too. Code written by a
> collegue was behaving very strangely. It turned out he used
> catch(...) adsorbing the exception in a DLL. The exception are
> used inside the DLL but catch(...) intercepted also memory
> faults hiding errors in a strange way.

It has been a while since I used VC++ (and things may have changed),
but I remember catch (...) sometimes trapped normal OS SEHs that would
otherwise be "resumed" without the application being aware that
anything had happened. Having unwound the stack this meant that there
was no way to recover.

> After some thinking I've come to the conclusion that catch(...)
> is good only if you are going to terminate the program

No, if things are so bad that you are going to terminate the program
do just that! Don't mess about unwinding the stack.

Anyway, there is a definite (although occasional) need for such
constructs as:

try {
. . .
}
catch (...) {
. . .
throw;
}

> (may be
> after some last desperate tentative to save something - but I'm
> not sure if I like that) as adsorbing an unknown event doesn't
> describe what I call a robust program... it's just code that
> *hide* errors and that cripple my documents instead of dying
> immediately as it should.

I agree that errors shouldn't be hidden.

> To not make me waste last hour on
> my WP doc it make me waste last *month* crippling its internal
> structure with a bad save that I'll discover only after a
> long time (just after all backups got a corrupted version,
> Murphy says).
>
> I think however that MS is not violating anything doing that...
> writing out of an array is Undefined Behaviour and performing
> a stack unwinding until it gets to a catch(...) is something
> that may happen once you enter the dark territories of UB.

This is a "quality of implementation" issue: the bad choice that MS
has made that causing "unknown events" to be hidden by code that is
perfectly reasonable C++.

> So using catch(...) to adsorb an exception is in my opinion a
> "don't",

And so is using catch (const my_exception&) to adsorb an exception.

> but I think MS did a good thing with current behaviour
> instead of formatting my hard disk (UB may mean that too).

I don't think I'd feel grateful that someone blew my arm off (instead
of blowing my head off). You clearly think differently.

> If your program got to a catch(...) and that is not because
> of one of your throws then you already violated the rules,
> so I wouldn't complain ... you were anyway just going to
> kill your program immediately with a loud yell, right ?

But if I don't own all of the code in the program (eg because I'm a
library author) then I may not have any control of the range of [C++]
exceptions that propagate.
--
Alan Griffiths <al...@octopull.demon.co.uk> ACCU Chairman
<ch...@accu.org>
http://www.octopull.demon.co.uk/ http://accu.org/

David Abrahams

unread,
Jul 21, 2002, 5:39:19 AM7/21/02
to

"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
news:3d3896a8....@news.online.no...

> On 19 Jul 2002 06:33:20 -0400, "David Abrahams"
> <david.a...@rcn.com> wrote:
>
> >
> >"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
> >news:3d359f82...@news.online.no...
> >
> > > So one doesn't really have the option to do much about the
> > > internal exception cleanup... That's why I didn't understand
> > > how to easily guard against the MSVC (and possibly other
> > > compilers')
> >
> >This is an MSVC-specific bug which I've never seen elsewhere. Vague
> >implications to the contrary are just FUD-fodder.
>
> I had to look up what "FUD" means, found an explanation at
> [http://www.geocities.com/SiliconValley/Hills/9267/fuddef.html].
>
> Hm. I do read some journals and haven't seen any such tactics
> lately, or indeed in many years, regarding C++ compilers. Perhaps
> you could provide an example? (E.g. in a new thread.)

You just supplied one, by implying that a bug in one implementation of EH
might have somehow been magically duplicated by many other EH
implementations.

> >You can't fix the compiler. I said to work around it you need to
exercise
> >care in the design of your exception classes.
> >
> >If you have data with a non-trivial destructor in your exception object,
> >hold it by-pointer. When the pointer gets deleted in the destructor,
make
> >sure you set it to 0 so that another deletion is innocuous. Or, you can
use
> >auto_ptr<>s or boost::shared_ptr<>s and reset() them in the exception's
> >destructor.
>
> Thanks, but since this won't work with exceptions outside one's
> control the conclusion seems to be that:
>
> the technique can't be (generally) used with the MSVC compiler,

Not with MSVC6, but that's obsolete. Surely nobody uses that compiler
anymore <wink>? VC7 works fine

> i.e. for Windows programming, but is supported by both the
> standard and actual compilers on other platforms.

And by actual compilers on the Windows platform, such as:

Metrowerks CodeWarrior Pro8
Intel C++ 6.0
MinGW gcc 2.95.3
Cygwin gcc 3.1

> > > Main question is also still there: does this generally work
> > > on other compilers
> >
> >Generally, yes.
> >
> >(i.e., are they now standard-compliant)?
> >
> >That's a different question. Generally, no (c.f. export).
>
> Sad to hear that. Perhaps a redesign of "export" should be
> considered for the next version of the standard?

Be my guest!

-Dave

Alf P. Steinbach

unread,
Jul 21, 2002, 10:07:55 AM7/21/02
to
On 21 Jul 2002 05:39:19 -0400, "David Abrahams" <david.a...@rcn.com>
wrote:

>
>"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
>news:3d3896a8....@news.online.no...
> > On 19 Jul 2002 06:33:20 -0400, "David Abrahams"
> > <david.a...@rcn.com> wrote:
> >
> > >
> > >"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in
> > message >news:3d359f82...@news.online.no...
> > >
> > > > So one doesn't really have the option to do much about the > >

> > internal exception cleanup... That's why I didn't understand > >
> > how to easily guard against the MSVC (and possibly other > >
> > compilers') >
> > >This is an MSVC-specific bug which I've never seen elsewhere.
Vague
> > >implications to the contrary are just FUD-fodder.
> >
> > I had to look up what "FUD" means, found an explanation at
> > [http://www.geocities.com/SiliconValley/Hills/9267/fuddef.html].
> >
> > Hm. I do read some journals and haven't seen any such tactics
> > lately, or indeed in many years, regarding C++ compilers. Perhaps
> > you could provide an example? (E.g. in a new thread.)
>
>You just supplied one, by implying that a bug in one implementation of
>EH might have somehow been magically duplicated by many other EH
>implementations.

That's the answer I'd hoped I'd not get.

There's nothing "magical" about similar bugs occuring in compilers. On
the contrary it's a natural expectation, born out by experience. And the
occurrence of that (or similar) bug, in C++ compilers in general, had at
that point become the main topic of this thread, so keeping the
possibility open had nothing to do with implying this or that -- and
least of all with employing FUD tactics.

I'm glad you've now resolved the technical interpration of the question
(below).


>...


> > Thanks, but since this won't work with exceptions outside one's
> > control the conclusion seems to be that:
> >
> > the technique can't be (generally) used with the MSVC compiler,
>
>Not with MSVC6, but that's obsolete. Surely nobody uses that compiler
>anymore <wink>? VC7 works fine

Many probably do. Microsoft supplies both 6 and 7 with MSDN.


>
> > i.e. for Windows programming, but is supported by both the standard
> > and actual compilers on other platforms.
>
>And by actual compilers on the Windows platform, such as:
>
>Metrowerks CodeWarrior Pro8
>Intel C++ 6.0
>MinGW gcc 2.95.3
>Cygwin gcc 3.1
>

Thanks, I think that settles the question! (Well, except for Cygwin g++
2.95.3... And... ;-) ).

Cheers,

- Alf

Alf P. Steinbach

unread,
Jul 22, 2002, 7:10:18 AM7/22/02
to
On 17 Jul 2002 06:35:42 -0400, jhy...@ieee.org (Jim Hyslop) wrote:
>...

>Actually, there is one thing I *really* like about MS's structured
>exceptions, and that's the "finally" clause - the code in that block
>always executes, no matter which handler handled the exception, and no
>matter whether the exception was completely handled or re-thrown. That,
>I think, would be a useful feature for C++ to incorporate. I keep
>meaning to add it to the "C++0x Wish List" thread in comp.std.c++ :-)

In C++ a nested try-catch can do the job of "finally":


struct NormalReturnException: std::exception { /* whatever */ };

void f()
{
bool isNormalReturn = false;
try
{
try
{
myBusinessLogic();
throw NormalReturnException(); // Normal return.
}
catch( NormalReturnException const& )
{
isNormalReturn = true;
throw;
}
catch( ARealException const& x )
{
// Cleanup for ARealException, then
throw;
}
// Etc.
catch( ... )
{
myFinallyClauseLogic();
if( !isNormalReturn ) throw;
}
}


Of course, it might be tad inefficient...

Also, needs to be adjusted if "ARealException" shouldn't be rethrown
(I haven't thought about that, details).

Cheers,

- Alf

David Abrahams

unread,
Jul 23, 2002, 4:22:27 PM7/23/02
to

"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
news:3d3a899c....@news.online.no...

Sorry, that's not the way I saw it. You were the first to raise the idea
that other compilers might misbehave in this particular way. We weren't
talking about "similar" bugs, we were talking about this one. Lots of bugs
could be called similar which don't have anything to do with EH or the
try-block-rethrow construct under discussion. I've seen all kinds of
problems crop up in odd cases with compiler-generated destructor calls, for
example, and we're not discussing avoiding destructors because they're
unreliable.

> , so keeping the
> possibility open had nothing to do with implying this or that -- and
> least of all with employing FUD tactics.

Well, I appreciate that it might not've been your intention, but your
parenthesized aside had that effect.

Suppose I find a compiler which destroys temporaries early in situations
like this (I actually found this bug the other day, and not in VC++):

template <class T>
void f(T const& x)
{
T const& y = modified(x);
y.func(); // whoops, the temporary is gone!
}


Is there any reason to think that my other compilers are going to have
trouble with this legal code? If you think so, I submit you're living in a
state of Fear, Uncertainty, and Doubt. The effect of taking such an approach
can be especially debilitating if your experiences are based on an outdated
compiler with lots of problems (ahem!)

> I'm glad you've now resolved the technical interpration of the question
> (below).

You're welcome.

> > > the technique can't be (generally) used with the MSVC compiler,
> >
> >Not with MSVC6, but that's obsolete. Surely nobody uses that compiler
> >anymore <wink>? VC7 works fine
>
> Many probably do. Microsoft supplies both 6 and 7 with MSDN.

Perhaps you missed my <wink>? Here, I'll amplify it to make it a little
easier to see:

<3.14e16 wink>

How's that?

> > > i.e. for Windows programming, but is supported by both the standard
> > > and actual compilers on other platforms.
> >
> >And by actual compilers on the Windows platform, such as:
> >
> >Metrowerks CodeWarrior Pro8
> >Intel C++ 6.0
> >MinGW gcc 2.95.3
> >Cygwin gcc 3.1
> >
>
> Thanks, I think that settles the question! (Well, except for Cygwin g++
> 2.95.3... And... ;-) ).

There you go again...

Well, I can <wink> again, since surely nobody's using cygwin gcc 2.95.3 now
that 3.1 is released?

Cygwin gcc 2.95.3 works on this example also. However, GCC 2.95.3 has other
EH bugs on some platforms which rarely crop up, so if you demand absolute
reliability on all platforms including obsolete compilers you should never
use EH at all.

-Dave

Alexander Terekhov

unread,
Jul 23, 2002, 4:28:05 PM7/23/02
to

Doug Harrison wrote:
>
> Hillel Y. Sims wrote:
>
> >catch (std::exception&) is all about catching all C++ exceptions. catch
> >(...) is specifically about catching anything the platform might possibly
> >throw at you (such as access violation) that lives on the same native
> >runtime mechanism on which C++ exception-handling is implemented, without
> >any knowledge of its context or type.
>
> People often think that's a good idea. Here are some sample messages
> explaining why I completely disagree with them:
>
> http://groups.google.com/groups?selm=eW%23ZKH8P%23GA...@uppssnewspub05.moswest.msn.net
> http://groups.google.com/groups?selm=k9etqs855giltd5se...@4ax.com

: Now, suppose you had the following sequence:
:
: // Begin C++ exception-free code.
: ... // Causes an access violation due to a bug.
: // End C++ exception-free code.

And now, suppose you had the following sequence:

// Begin C++ code.
... // Causes an UNEXPECTED {std::}whatever {logic_error/
// domain_error/invalid_argument/length_error/out_of_range/
// runtime_error/range_error/overflow_error/underflow_error/
// etc. *usually* >>UNEXPECTED<< stuff...
//
// >>due to a bug<<.
//
// End C++ code.

> FWIW, I've been arguing this point for eight years, and I've never
> heard a reasonable argument why catch(...) should catch untranslated
> Win32 structured exceptions.

It should. And that's non-issue [implementation-defined unwinding and
"similar" problems {IMO} with C++ ex.specs. aside] if you catch *ONLY*
things you KNOW/REALLY want/need, AFAICS.

regards,
alexander.

Francis Glassborow

unread,
Jul 23, 2002, 4:29:25 PM7/23/02
to
In article <3D3547F2...@web.de>, Alexander Terekhov
<tere...@web.de> writes
>
>Francis Glassborow wrote:
> >
> > In article <3D326BB4...@web.de>, Alexander Terekhov
> > <tere...@web.de> writes
> > >
> > >Do you see the point? Or am I missing and/or misunderstanding
> > >something?
> >
> > Yes, you have been twice asked what 'khm' stands for. The first time you
> > gave a link that does not appear to answer the question and this time
> > you have provide two screen fulls that still does not appear to answer
> > the question.
>
>Okay, I'll try one more time (see some comp.std.c++ archive for the full
>context -- Subject: Re: throw() can be good for optimization):

OK, clearly we must try guessing what khm stands for, my offer is:

Knowledge Helps Mentation.

Any others?


>
>
>Francis Glassborow wrote:
>[...]
> > An empty throw spec. is just an ES and is treated the same way as all
> > others (we try to avoid special casing things). While it is true that
> > the unexpected_handler cannot do anything to allow the process to
> > continue because it cannot replace the exception with another, in
> > general (other than for empty throw specs) this is possible and the
> > rules (reasonably IMO) state that such a catch is effectively handling
> > the original exception.
>
>What "such catch"? I am talking about stack-unwinding
>PRIOR to unexpected()/terminate() invocation and "problems"
>(as it seems to me) resulting due to this behavior, for
>example:

If a programmer elects to use and empty throw specification one of the
consequences is the behaviour you describe. If you do not want this
behaviour you will have to write your code differently. The point is
that the unexpected_handler is deemed by the language to have handled
the exception and so the stack will be unwound. This is necessary to
allow the handler to do something reasonable and throw another
exception. Of course in the case of an empty throw spec there is no
other type that can be used but empty throw specs are used in exactly
those cases where the programmer is certain that exceptions cannot reach
this point.


--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Alexander Terekhov

unread,
Jul 23, 2002, 6:48:26 PM7/23/02
to

Matthew Collett wrote:
[...]

> Yet another reason never to bother with exception specifications, I
> suppose.

You probably mean this publication:

http://www.gotw.ca/publications/index.htm
(Mill #22 A Pragmatic Look at Exception Specifications,
C/C++ Users Journal, 20(7), July 2002.)

No; and I believe strongly that "morals" like these:

"Moral #1: Never write an exception specification.

Moral #2: Except possibly an empty one, but if I were
you I'd avoid even that."

send the wrong message... to the C++ standards committee members in
the first place. C++ exception handling should rather be *revisited*
by the committee; perhaps "extended" [10-o'clock-wish-list] and, more
importantly, FIXED.

Oh, BTW, w.r.t. exception handling/performance/throw(), consider this:

http://www.computer.org/concurrency/pd2000/p4072abs.htm

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

< quote from the article >

"KNOWN FUNCTIONS THAT CAN'T
THROW

When exceptions are enabled, there
is a landing pad and table space overhead
for each call site. This overhead can be
avoided for specific functions that are
known not to throw. These functions
typically include C++ runtime library
functions called implicitly by the compiler,
functions of the C library, because
they are known not to throw exceptions,
and functions that are marked as not
throwing exceptions through an empty
exception specification. ...."

"random" refs:

http://groups.google.com/groups?selm=48o7bu4vu3d52u4tkrul73458ja50r4vtl%404ax.com
http://groups.google.com/groups?selm=3CB59C36.B4C0008A%40web.de
(Subject: Re: C++ and threads; link: ...3-C-B-5-9-C-3-6-...)

http://groups.google.com/groups?selm=3CE664A6.A5D4B620%40web.de
http://groups.google.com/groups?selm=3CC86F8C.94EFB52C%40web.de
http://groups.google.com/groups?selm=3CC97E16.3191C096%40web.de
(Subject: Re: A half serious proposal: overloaded destructors)

http://groups.google.com/groups?selm=230879.F56DA7E1%40web.de
(Subject: Re: Some issues with Technical Report on C++ Performance (DRAFT))

"[...]
> I don't know what Herb's answer would be, but IMO it's not really possible
> to protect anyone from most "really bad things", except by carefully coding
> to avoid them. If you have better ideas about this, I guess the world would
> love to know them.

Well, with "protection" I meant something that would prevent the
propagation [out of throw() routines, to begin with] of anything
raised [and left 'unhandled' or re-raised] due to "really bad
things" or whatever.

IOW, I believe strongly that a) TWO-PHASE exception processing
shall be declared MANDATORY[1] by the C++ standards committee
and b) exception specifications shall be revised/fixed so that
they shall NOT require unneeded/harmful unwinding on ex.specs.
violation [way up to that implicit 'catch(...)' handler that's
meant to invoke std::unexpected(); that should better be done
>>AT THROW POINT<< in the next version of C++, IMNSHO]."

regards,
alexander.

--
"Finally, if I take my best guess as to what you're complaining about in the
standard, I have much bigger fish to fry for C++0X. EH is mostly pretty
well-specified in the standard IMO. BTW I had nothing to do with the core
language definition of EH; only understanding how to use it and apply it to
the library specification." -Dave, comp.std.c++

Rob

unread,
Jul 23, 2002, 6:54:21 PM7/23/02
to
"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
news:3d389af9....@news.online.no...

> On 17 Jul 2002 06:35:42 -0400, jhy...@ieee.org (Jim Hyslop) wrote:
> >...
> >Actually, there is one thing I *really* like about MS's structured
> >exceptions, and that's the "finally" clause - the code in that block
> >always executes, no matter which handler handled the exception, and no
> >matter whether the exception was completely handled or re-thrown. That,
> >I think, would be a useful feature for C++ to incorporate. I keep
> >meaning to add it to the "C++0x Wish List" thread in comp.std.c++ :-)

I wouldn't. I've seen a few too many examples in C++ code using Microsoft
extensions where that effective "finally" clause is used as a catch all for
certain problems caused by bad design. With sensible use of "constructor
grabs resources, destructor releases" a finally clause should not be
necessary
in C++.

As an aside, the finally clause is needed in Java because the point where
the "finalizer" of an object is called is not explicitly defined --- the
decision
of when to call it is made by the garbage collector, and there is not even a
guarantee it *will* be called. But that issue does not arise in well
structured
and designed C++ code.

>
> In C++ a nested try-catch can do the job of "finally":
>

> [Example snipped]


>
>
> Of course, it might be tad inefficient...

Compared with what? The efficiency (or otherwise) of an exception handling
scheme in C++ is really a quality of implementation issue for the compiler.
The mechanism behind the scenes required to implement a "finally"
clause would probably not be fundamentally different from a nested
try/catch implementation; the only difference would be that the outer
try/catch block would be done implicitly by the compiler rather than
in code. From an efficiency viewpoint, there should be little real
difference.

Ken Hagan

unread,
Jul 23, 2002, 7:12:02 PM7/23/02
to
"Alan Griffiths" <al...@octopull.demon.co.uk> wrote ...

>
> It has been a while since I used VC++ (and things may have changed),
> but I remember catch (...) sometimes trapped normal OS SEHs that would
> otherwise be "resumed" without the application being aware that
> anything had happened. Having unwound the stack this meant that there
> was no way to recover.

[off topic, at least for clc++m, but this is presented as a killer VC design
bug
sufficiently often that non-MSVC users might appreciate the clarification]

Unless you use signals, this isn't true.

The OS emits structured exceptions for some events that the CRT expects to
handle using signals, like SIGSEGV, SIGILL and SIGFPE. If you have
registered a handler for these, then it is called by an SEH block that wraps
your "main()" function. If you use catch(...) then you stop the search for
an
SEH handler from reaching this point. (So-called "vectored" SEH handlers
would presumably allow MS to move this translation code out of the call
stack, but they aren't supported prior to Win2K.)

However, there is so little that can be portably done with signals that most
people never use them, so they are never bothered by this. Furthermore,
Win32 GUI programs and COM servers already have the SEH equivalent
of catch(...) inserted by the operating system around window procedures
and server stubs (respectively) so anything MS wrap around main() is a
total irrelevance. In any case, the whole environment is such a mish-mash
of code from different compilers and run-times that I would classify the
whole
lot as a non-hosted implementation, and then most bets are off anyway.

(It is sometimes alleged that stack guard pages are obstructed by catch(...)
but this is an urban myth, since those faults are not passed on to user
space.)

David Abrahams

unread,
Jul 23, 2002, 7:46:31 PM7/23/02
to

"Hillel Y. Sims" <use...@phatbasset.com> wrote in message
news:beMZ8.87143$6r.29...@news4.srv.hcvlny.cv.net...

> If every bit of your code ONLY throws and catch exceptions inherited from
> std::exception, then by inductive reasoning you never need to worry about
> catch(...) (even from generic templated code) and you never need to worry
> about intercepting OS exceptions regardless of the platform.

Incorrect. Somebody else's code might throw something else at me, even if
every bit of my code throws and catches std::exception-derived classes (it
does, BTW, because... well, why shouldn't it?)

> I won't go
> quite so far as to say it's a mistake in C++ that you can throw exceptions
> other than inherited from std::exception, but I will strongly suggest it
is
> very poor form for programmers to do so (and I do note that all std
library
> exceptions inherit from std::exception). Please, anyone, show me one
aspect,
> minor or major, whereby there is any downside to inheriting all your
> exception objects from std::exception (other than having to type a few
extra
> characters to define the object..)?

They all get a virtual table. That could be an issue for some
resource-constrained environments. The exception-specification on the what()
method might cause code pessimization on some platforms.

> As far as other aspects of catch(...), let me just try to make a couple of
> points that will hopefully cover all the issues:
>
> 1) The "catch(...) { throw; }" rethrow idiom -- IF you _always_ _rethrow_
> the UNALTERED exception from a catch(...) block (and it is fairly
> unconscionable to swallow it / "translate" it... so far Jim Hyslop and
> Andrea Griffini have posted examples of the evil that happens when you
> swallow unknown exceptions; and you can't legitimately try to translate it
> either -- how can you even try to translate something that you can't even
> possibly know what it is???)

Red herring. You don't know what a std::exception is either -- it could be
any derived class.

> -- if you rethrow the exception, this is not AS
> bad as swallowing it. However, there are _still_ two undesirable side
> effects from result even this seemingly harmless _forced_ unwinding:
> - high importance: if you are unwinding during a hardware exception,
you
> may end up corrupting persistent extra-process state (eg. disk files,
> network, etc). Since the fact that a hardware exception has been raised
> indicates that there is unknown corruption in your program state, any
> unwinding at all in this state is usually a bad idea. Much better to rely
on
> automatic object (have you tried Alexandrescu/Marginen's ScopeGuard
package?
> ON_BLOCK_EXIT is a safe 99%-"finally" for C++! It's fabulous!!) /

Why do you think the code in a catch(...) block is any more prone to corrupt
than the code in a destructor is?

> std::exception-only unwinding, in which case you can usually avoid forced
> unwinding due to a fatal program state corruption problem (assuming your
> platform doesn't force it on you, but that's clearly an aspect of QoI; at
> least VMS doesn't force it unless there is catch(...)). (and yes, you can
> also avoid this problem by not corrupting your program state in the first
> place, ha ha..)

So what happens instead? Your program crashes anyway?

> This is one objection to even using the "catch(...) { throw; }"
form -
> it can cause unintended permanent data corruption.

I don't see how it's special in that regard.

> - moderate importance: it can interfere with post-crash debugging.

This one I understand.

> At
> least on VMS, the stack traceback / core dump mechanism which is triggered
> when an exception causes a program to terminate can only snapshot the
> deepest level of the call stack which is still available when the
exception
> propagates outside of main(). If a catch(...) is encountered along the
way,
> the entire portion of the call stack deeper than that is unwound and
cleaned
> up before the exception is rethrown, and important debugging context is
> permanently lost. When the exception finally propagates outside main() and
> causes the abnormal termination / stack trace / core dump, the call stack
no
> longer shows any meaningful information past the last catch(...) block
which
> was encountered.

Yep, that's bad stuff. Isn't there a way to hook the low-level crash handler
on VMS so it just dumps core immediately?

> Well I'm sure that some people may think "QoI!" about this point. But
> please consider again that this is the reality behind some OSs,

Reality is important.

> and the
> ability to avoid catch(...) completely through use of
std::exception-derived
> exceptions

That's a false premise for a library writer, unless I want to impose that
requirement on my users (and I don't).

> removes this entire issue from the table without having to worry
> about if/when a vendor is going to fix their OS or if there are
> platform-specific hooks to trap fatal errors and in the meantime we're
stuck
> scratching our heads wondering why std::vector constructor's catch(...)
> block shows up as the last thing on the call stack and what could have
> possibly actually triggered the exception in the user-defined type?


Uh, yeah, now that you mention it: on the reality side, my standard library
implementation is likely to use catch(...) anyway.


> You, as the programmer of this object

> may be legitimately concerned that that function could throw an exception,
> and that would be a Bad Thing to allow to propagate outside your
destructor.
> Thus, the advice commonly encountered in various print media by major
> authors and other outlets would be to do something like the following:
> Obj::~Obj()
> {
> try {
> dll_cleanup_function_that_does_zeus_knows_what();
> }
> catch (...) {}
> }
>
> Can we all agree that this is Very Bad in the presence of hardware
> exceptions that may come through the catch(...)?

I'm not sure. Wasn't the program doomed to crash anyway? If hardware
exceptions are catchable, I'd write:

try {
dll_cleanup_function_that_does_zeus_knows_what();
}
catch(hardware_exception const&) { throw; }
catch (...) {}

If not, I hope that someone other than Zeus (i.e. documentation) can tell me
what exceptions the function can throw, so:

try {
dll_cleanup_function_that_does_zeus_knows_what();
}
catch(those_exceptions const&) {}

should be OK.

> (I am not claiming that
> those who have suggested that idiom were somehow "dumb" or did not know
what
> they were talking about -- rather this seems to be a somewhat
under-explored
> area and is not even an issue at all on most unix boxes which many people
> are familiar with, so I can understand why this advice may have been given
> in seemingly good conscience in the past, but I do feel it is somewhat
> misguided in light of the hardware exception issue.)

Well, I think I've explored the issue pretty thoroughly since I have to
support Windows.

<snip>

> The only really safe and portable alternative is to rely on the inductive
> reasoning available whereby all application exceptions are inherited from
> std::exception.

That's not really the only way. It's a simple way, but you can have as many
exception hierarchies as you want as long as you know all the root classes.

> Any programmer who wishes to use C++ exceptions really should have a good
> understanding of this interaction, that exists and is probably not going
> away anytime soon, and how to safely work with it, or they will actually
end
> up with less-robust software than they would have had had they continued
to
> use the old non-exception style of programming. If you are on various unix
> boxen, then you apparently don't even need to consider this issue at all,
> and if you're on Windows, then you apparently have a platform-specific
> workaround available, so good luck with that (assuming it is 100%
reliable),

It's not (I detailed the way in which it fails in my previous post). But
it's good enough for many purposes.

> but PLEASE consider that there are not always reliable platform-specific
> workarounds and that the simple act of always inheriting your exceptions
> from std::exception does provide a fully-portable and completely robust
> basis for automatic and absolute separation of all hardware/software
> exception interaction concerns.

assuming you have control over every exception that gets thrown.

Note that 17.4.4.8/3 gives your standard library implementation license to
throw exceptions not derived from std::exception:

"Any other functions
defined in the C++ Standard Library that do not have an
exception-specification may throw
implementation-defined exceptions unless otherwise specified."

-Dave

Doug Harrison

unread,
Jul 24, 2002, 11:45:29 AM7/24/02
to
Alexander Terekhov wrote:

That's a different scenario. In my C++ exception-free code sequence, I
can use all of C++ that doesn't throw exceptions. For example, I can
push_back() into a vector<int> whose capacity() > size(). I can use
the C subset, so I can use all the C Standard Library, all of the
Win32 API, call COM methods, etc. I discussed this in this recent
thread:

http://groups.google.com/groups?threadm=1h1v8u82mhr3iidgd1aeb11sekq80bapev%404ax.com&rnum=1&prev=/groups%3Fq%3Dg:thl1800401586d%
26dq%3D%26hl%3Den%26lr%3Dlang_en%26ie%3DUTF-8%26safe%3Doff%26selm%3D1h1v8u82mhr3iidgd1aeb11sekq80bapev%25404ax.com

In my example, the OS will normally handle an access violation by
displaying an error box, which tells me about the error and allows me
to debug the program or terminate it. An outer catch(...) subverts
this process, and a normally program-terminating bug causes my program
to unwind the stack on its way to my C++ exception recovery code. Upon
executing the bug, the program enters an unknown state, but it's
allowed to continue, as if a C++ exception I designed for had been
thrown.

In your example, you threw a C++ exception when you shouldn't have,
and it could be caught by a std::exception handler, not just
catch(...). There's no expectation of different behavior here. C++
exception handlers are supposed to catch C++ exceptions! So while you
may have a bug, I don't believe you have any reason to complain.

>> FWIW, I've been arguing this point for eight years, and I've never
>> heard a reasonable argument why catch(...) should catch untranslated
>> Win32 structured exceptions.
>
>It should. And that's non-issue [implementation-defined unwinding and
>"similar" problems {IMO} with C++ ex.specs. aside] if you catch *ONLY*
>things you KNOW/REALLY want/need, AFAICS.

Well, no. The point is that catch(...) catches non-C++ exceptions,
which destroys its usefulness for catching C++ exceptions.

Alexander Terekhov

unread,
Jul 24, 2002, 4:19:54 PM7/24/02
to

Doug Harrison wrote:
[...]

> >> FWIW, I've been arguing this point for eight years, and I've never
> >> heard a reasonable argument why catch(...) should catch untranslated
> >> Win32 structured exceptions.
> >
> >It should. And that's non-issue [implementation-defined unwinding and
> >"similar" problems {IMO} with C++ ex.specs. aside] if you catch *ONLY*
> >things you KNOW/REALLY want/need, AFAICS.
>
> Well, no. The point is that catch(...) catches non-C++ exceptions,
> which destroys its usefulness for catching C++ exceptions.

My, consider the following "mixture" of C/SEH and C++ exceptions:

C:\Documents and Settings\Terekhov>cl /EHsc seh3.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.

seh3.cpp
Microsoft (R) Incremental Linker Version 7.00.9466
Copyright (C) Microsoft Corporation. All rights reserved.

/out:seh3.exe
seh3.obj

C:\Documents and Settings\Terekhov>seh3
....1
A: done.
....2
B: done.
....wanna rely on SEH for argument validation....
....3
C: done.
....throw std::invalid_argument exception....
A: oh, caught something!
....throw std::invalid_argument exception....
B: oh, caught something!
....wanna rely on SEH for argument validation....
C: oh, caught something!

C:\Documents and Settings\Terekhov>type seh3.cpp

#include <windows.h>

#include <exception>
#include <iostream>

void do_something_A( const int* save_this_value,... )
{
if ( 0 != save_this_value ) {
if ( IsBadReadPtr( save_this_value, sizeof( *save_this_value ) ) ) {
std::cout << "....throw std::invalid_argument exception...." << std::endl;
throw std::invalid_argument("");
}
std::cout << "...." << *save_this_value << std::endl;
/**/
}
/**/
}

void invalid_B_arg()
{
std::cout << "....throw std::invalid_argument exception...." << std::endl;
throw std::invalid_argument("");
}

int load_B_arg( const int* save_this_value )
{
_try {
return *save_this_value;
}
_except( GetExceptionCode() == STATUS_ACCESS_VIOLATION ) {
invalid_B_arg();
}
return 0; // shut up, stupid
}

void do_something_B( const int* save_this_value,... )
{
if ( 0 != save_this_value ) {
int value = load_B_arg( save_this_value );
std::cout << "...." << value << std::endl;
/**/
}
/**/
}

void do_something_C( const int* save_this_value,... )
{
if ( 0 != save_this_value ) {
std::cout << "....wanna rely on SEH for argument validation...." << std::endl;
int value = *save_this_value;
std::cout << "...." << value << std::endl;
/**/
}
/**/
}

int main()
{
int value = 1;
do_something_A( &value );
std::cout << "A: done." << std::endl;
value = 2;
do_something_B( &value );
std::cout << "B: done." << std::endl;
value = 3;
do_something_C( &value );
std::cout << "C: done." << std::endl;
try {
do_something_A( reinterpret_cast< const int* >(1) );
}
catch(...) {
std::cout << "A: oh, caught something!" << std::endl;
}
try {
do_something_B( reinterpret_cast< const int* >(2) );
}
catch(...) {
std::cout << "B: oh, caught something!" << std::endl;
}
try {
do_something_C( reinterpret_cast< const int* >(3) );
}
catch(...) {
std::cout << "C: oh, caught something!" << std::endl;
}
}

C:\Documents and Settings\Terekhov>

regards,
alexander.

Sergey P. Derevyago

unread,
Jul 24, 2002, 4:20:12 PM7/24/02
to
David Abrahams wrote:
> > 1) Never use catch(...), especially in portable code.
> How would you write uninitialized_fill without catch(...)?
IMHO RAII could really help here ("Who says writing exception-safe code is
trying?" :). For example

template <class ForwardIterator, class T>
void uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x)
{
ForwardIterator curr=first;
SomeHelper<ForwardIterator> sh(first, curr); // saves references
for ( ; curr!=last; ++curr)
_Construct(&*curr, x);
sh.ok(); // don't destruct in ~SomeHelper()
}

instead of

template <class ForwardIterator, class T>
void uninitialized_fill(ForwardIterator first, ForwardIterator last,
const T& x)
{
ForwardIterator curr=first;
try {
for ( ; curr!=last; ++curr)
_Construct(&*curr, x);
}
catch (...) {
_Destroy(first, curr);
throw;
}
}

--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

Alexander Terekhov

unread,
Jul 24, 2002, 4:24:12 PM7/24/02
to

David Abrahams wrote:
[...]

> Uh, yeah, now that you mention it: on the reality side, my standard library
> implementation is likely to use catch(...) anyway.

< a couple of days earlier >

Alexander Terekhov wrote:
>
> David Abrahams wrote:
> [...]


> > How would you write uninitialized_fill without catch(...)?
>

> Show me the code, please.
>
> [...]
> > Yeah, but if you're interfacing with other peoples' libraries, or writing
> > templates, or writing frameworks that supply base classes with virtual
> > functions, you don't always have control over the types of exceptions that
> > get thrown. Writing certain kinds of exception-neutral code efficiently can
> > be extremely difficult without catch(...).
>
> Examples?

< Still no reply; Okay, "Bringing the mountain to Mmm.." er. Abrahams ;-) >

C:\IBMCPP40\include\memory

------
<snip>
/********************************************************************/
/* <memory> header file */
/* */
/* VisualAge C++, Version 4.0 */
/* Licensed Material - Property of IBM */
/* */
/* 5801-AAR and Other Materials */
/* */
/* (c) Copyright IBM Corp 1991, 1998. All rights reserved. */
/* */
/* */
/* Licensed Materials. */
/* */
/* Dinkum C++ Library */
/* Copyright (c) 1998. Licensed to IBM Corp. and its suppliers. */
/* */
/********************************************************************/
<snip>
// TEMPLATE FUNCTION uninitialized_fill
template<class _FI, class _Ty> inline
void uninitialized_fill(_FI _F, _FI _L, const _Ty& _X)
{for (; _F != _L; ++_F)
_Construct(&*_F, _X); }

<snip>
/*
* Copyright (c) 1995 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/

/*
* This file is derived from software bearing the following
* restrictions:
*
* Copyright (c) 1994
* Hewlett-Packard Company
<snip>
------


C:\Program Files\Microsoft Visual Studio\VC98\Include\memory

------
<snip>
// TEMPLATE FUNCTION uninitialized_fill
template<class _FI, class _Ty> inline
void uninitialized_fill(_FI _F, _FI _L, const _Ty& _X)
{for (; _F != _L; ++_F)
_Construct(&*_F, _X); }

<snip>
/*
* Copyright (c) 1995 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/

/*
* This file is derived from software bearing the following
* restrictions:
*
* Copyright (c) 1994
* Hewlett-Packard Company
<snip>
------


C:\Program Files\Microsoft Visual Studio .NET\Vc7\include\memory:

------
<snip>
// TEMPLATE FUNCTION uninitialized_fill
template<class _FwdIt,
class _Tval> inline
void uninitialized_fill(_FwdIt _First, _FwdIt _Last, const _Tval& _Val)
{ // copy _Val throughout raw [_First, _Last)
_Uninit_fill(_First, _Last, _Val, _Ptr_cat(_First, _First));
}

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_BEGIN
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
_CATCH_ALL
for (; _Next != _First; ++_Next)
_Destroy(&*_Next);
_RERAISE;
_CATCH_END
}

<snip>
/*
* Copyright (c) 1992-2001 by P.J. Plauger. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/

/*
* This file is derived from software bearing the following
* restrictions:
*
* Copyright (c) 1994
* Hewlett-Packard Company
<snip>
----


C:\Documents and Settings\Terekhov\ABRAuhmmCADABRA.cpp:

----
<snip>

template< class _FwdIt >
class _Uninit_fill_cleanup {
_FwdIt const& m_First;
_FwdIt const& m_Last;
_FwdIt m_Next;
public:

_Uninit_fill_cleanup( _FwdIt const& _First, _FwdIt const& _Last ) :
m_First( _First ), m_Last( _Last ), m_Next( _First ) {
}

~_Uninit_fill_cleanup() {
if ( m_First != m_Last )
for (; m_First != m_Next; ++m_Next)
_Destroy(&*m_Next);
}

};

template< class _FwdIt, class _Tval >
inline void _Uninit_fill( _FwdIt _First, _FwdIt _Last, const _Tval& _Val ) {
_Uninit_fill_cleanup< _FwdIt > _Cleanup( _First, _Last );
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
}

<snip>
---

< dreams on >

template< context > // see "10-o'clock-wish-list"
class _Uninit_fill_cleanup {
typeof( context._First ) m_Next;
public:

_Uninit_fill_cleanup() :
m_Next( context._First ) {
}

~_Uninit_fill_cleanup() {
if ( context.m_First != context.m_Last )
for (; context.m_First != m_Next; ++m_Next)
_Destroy(&*m_Next);
}

};

template< class _FwdIt, class _Tval>
inline void _Uninit_fill( _FwdIt _First, _FwdIt _Last, const _Tval& _Val ) {
_Uninit_fill_cleanup< context > _Cleanup();
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
}

< dreams off >

regards,
alexander.

Alf P. Steinbach

unread,
Jul 24, 2002, 6:29:51 PM7/24/02
to
On 23 Jul 2002 18:54:21 -0400, "Rob" <nos...@does.not.exist> wrote:

>"Alf P. Steinbach" <alf_p_s...@yahoo.no.invalid> wrote in message
>news:3d389af9....@news.online.no...
> >

> > In C++ a nested try-catch can do the job of "finally":
> >
> > [Example snipped]
> >
> >
> > Of course, it might be tad inefficient...
>
>Compared with what? The efficiency (or otherwise) of an exception
handling
>scheme in C++ is really a quality of implementation issue for the
>compiler. The mechanism behind the scenes required to implement a
>"finally" clause would probably not be fundamentally different from a
>nested try/catch implementation; the only difference would be that the

>outer try/catch block would be done implicitly by the compiler rather
than
>in code. From an efficiency viewpoint, there should be little real
>difference.

It might be a tad inefficient because a throw, which must appear in the
handcrafted nested try-catch, is not as efficient as a goto, which would
be the likely compiler-generated code? The compiler can
(probably) do it more efficiently because it not only knows more about
the innards of the exception handling implementation, but it can tweak
that implementation to support "finally". At least, that's my thinking.
As I remember from earlier (1997-98?) discussions, Microsoft really
pushed hard for "finally" in the standardization process, but didn't
convince people that it was worthwhile. Perhaps because well-designed
C++ code should primarily rely on destructors.

Cheers,

- Alf

Alan Griffiths

unread,
Jul 25, 2002, 7:03:54 AM7/25/02
to
"Ken Hagan" <K.H...@thermoteknix.co.uk> wrote in message news:<1027329701.3321.0...@news.demon.co.uk>...

> "Alan Griffiths" <al...@octopull.demon.co.uk> wrote ...
> >
> > It has been a while since I used VC++ (and things may have changed),
> > but I remember catch (...) sometimes trapped normal OS SEHs that would
> > otherwise be "resumed" without the application being aware that
> > anything had happened. Having unwound the stack this meant that there
> > was no way to recover.
>
> [off topic, at least for clc++m, but this is presented as a killer VC design
> bug
> sufficiently often that non-MSVC users might appreciate the clarification]
>
> Unless you use signals, this isn't true.

[Still off topic, but it may shed light on the claims.]

I'm pleased to know it isn't true now - but it was at one time.
(Having lost several days of my life identifying the problem. This
would have been around 1994-1996.)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

David Abrahams

unread,
Jul 25, 2002, 7:09:20 AM7/25/02
to

"Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
news:3D3EA550...@iobox.com...

> David Abrahams wrote:
> > > 1) Never use catch(...), especially in portable code.
> > How would you write uninitialized_fill without catch(...)?
> IMHO RAII could really help here ("Who says writing exception-safe code is
> trying?" :). For example

Yes, but since you're the guy who's so concerned with efficiency, please try
to get your compiler to generate code for the first version that's as fast
as the code for the second version <wink>.

> template <class ForwardIterator, class T>
> void uninitialized_fill(ForwardIterator first, ForwardIterator last,
> const T& x)
> {
> ForwardIterator curr=first;
> SomeHelper<ForwardIterator> sh(first, curr); // saves references
> for ( ; curr!=last; ++curr)
> _Construct(&*curr, x);
> sh.ok(); // don't destruct in ~SomeHelper()
> }
>
> instead of
>
> template <class ForwardIterator, class T>
> void uninitialized_fill(ForwardIterator first, ForwardIterator last,
> const T& x)
> {
> ForwardIterator curr=first;
> try {
> for ( ; curr!=last; ++curr)
> _Construct(&*curr, x);
> }
> catch (...) {
> _Destroy(first, curr);
> throw;
> }
> }

The first version really does force the curr iterator onto the stack on
every compiler I know of, whereas in the second version most compilers will
keep it in a register (if it's a pointer).

-Dave

Alexander Terekhov

unread,
Jul 25, 2002, 11:19:54 AM7/25/02
to

David Abrahams wrote:
>
> "Sergey P. Derevyago" <non-ex...@iobox.com> wrote in message
> news:3D3EA550...@iobox.com...
> > David Abrahams wrote:
> > > > 1) Never use catch(...), especially in portable code. > > How

> would you write uninitialized_fill without catch(...)? > IMHO RAII
> could really help here ("Who says writing exception-safe code is >
> trying?" :). For example
>
> Yes, but since you're the guy who's so concerned with efficiency,
> please try to get your compiler to generate code for the first version

> that's as fast as the code for the second version <wink>.
>
> > template <class ForwardIterator, class T>
> > void uninitialized_fill(ForwardIterator first, ForwardIterator
last,
> > const T& x)
> > {
> > ForwardIterator curr=first;
> > SomeHelper<ForwardIterator> sh(first, curr); // saves references
> > for ( ; curr!=last; ++curr)
> > _Construct(&*curr, x);
> > sh.ok(); // don't destruct in ~SomeHelper()

I'd rather try to avoid such extra
"commit/dismiss/whatever-you-call-it",
see updated "dreams on" example below.

> > }
> >
> > instead of
> >
> > template <class ForwardIterator, class T>
> > void uninitialized_fill(ForwardIterator first, ForwardIterator
last,
> > const T& x)
> > {
> > ForwardIterator curr=first;
> > try {
> > for ( ; curr!=last; ++curr)
> > _Construct(&*curr, x);
> > }
> > catch (...) {
> > _Destroy(first, curr);

Here, imagine what could happen IF _Destroy() for some object would
suddenly THROW... and compare it with the "dreams on" example below.

> > throw;
> > }
> > }
>
> The first version really does force the curr iterator onto the stack
> on every compiler I know of, whereas in the second version most
> compilers will keep it in a register (if it's a pointer).

Red herring. <no wink>

< dreams on, syntax/keywords aside >

template< context > // see "10-o'clock-wish-list"
class _Uninit_fill_cleanup {
typeof( context._First ) m_Next;
public:

_Uninit_fill_cleanup() :
m_Next( context._First ) {
}

~_Uninit_fill_cleanup() {
if ( future_std::unwinding( this ) ) // see "10-o'clock-wish-list"


for (; context.m_First != m_Next; ++m_Next)
_Destroy(&*m_Next);
}

};

template< class _FwdIt, class _Tval>
inline void _Uninit_fill( _FwdIt _First, _FwdIt _Last, const _Tval& _Val
) {
_Uninit_fill_cleanup< context > _Cleanup();
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
}

< dreams off >

regards,
alexander.

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Alexander Terekhov

unread,
Jul 25, 2002, 11:48:37 AM7/25/02
to

Francis Glassborow wrote:
>
> In article <3D3547F2...@web.de>, Alexander Terekhov
> <tere...@web.de> writes
> >
> >Francis Glassborow wrote:
> > >
> > > In article <3D326BB4...@web.de>, Alexander Terekhov
> > > <tere...@web.de> writes
> > > >
> > > >Do you see the point? Or am I missing and/or misunderstanding
> > > >something?
> > >
> > > Yes, you have been twice asked what 'khm' stands for. The first
> > > time you gave a link that does not appear to answer the question
> > > and this time you have provide two screen fulls that still does
> > > not appear to answer the question.
> >
> >Okay, I'll try one more time (see some comp.std.c++ archive for the
> >full context -- Subject: Re: throw() can be good for optimization):
>
> OK, clearly we must try guessing what khm stands for, my offer is:
>
> Knowledge Helps Mentation.

Not {entirely} bad.

>
> Any others?
> >
> >
> >Francis Glassborow wrote:
> >[...]
> > > An empty throw spec. is just an ES and is treated the same way as
> > > all others (we try to avoid special casing things). While it is
> > > true that the unexpected_handler cannot do anything to allow the
> > > process to continue because it cannot replace the exception with
> > > another, in general (other than for empty throw specs) this is
> > > possible and the rules (reasonably IMO) state that such a catch is

> > > effectively handling the original exception.
> >
> >What "such catch"? I am talking about stack-unwinding
> >PRIOR to unexpected()/terminate() invocation and "problems" (as it
> >seems to me) resulting due to this behavior, for
> >example:
>
> If a programmer elects to use and empty throw specification one of the

> consequences is the behaviour you describe.

But this behavior HURTS. I guess, the only reason why we have it is that

someone thought that ex. specs can NOT, in general {e.g. archaic setjmp/
longjmp C exceptions "macros"}, be checked at throw point {in the
dynamic
context}; not invoking unwinding. A similar "thought" is probably also
the
reason why we have that "implementation-defined" bit w.r.t. unwinding
for
uncaught exceptions. I'm personally NOT sure however that "proper"
checking
can't be done even if using setjmp/longjmp EH... modern "tables"/"maps"
EH
aside, for a moment.

> If you do not want this
> behaviour you will have to write your code differently.

How? Get rid of exceptions altogether and simply abort()... instead
of throwing std::logic_error/std::invalid_argument/std::length_error/
std::out_of_range/std::runtime_error/std::range_error/std::overflow_erro
r/
std::underflow_error/etc, "for example"?! Ha! See the link below, to
begin
with.

> The point is
> that the unexpected_handler is deemed by the language to have handled
> the exception and so the stack will be unwound. This is necessary to
> allow the handler to do something reasonable and throw another
> exception. Of course in the case of an empty throw spec there is no
> other type that can be used but empty throw specs are used in exactly
> those cases where the programmer is certain that exceptions cannot
> reach this point.

Yeah, and now please check out the following [sort-of unexpected()/
terminate(), but in C/POSIX] thread:

http://www.opengroup.org/sophocles/show_archive.tpl?source=L&listname=
austin-group-l&first=1&pagesize=80&searchstring=abort%28%29&zone=G

Or, perhaps, you might want to save some time and instead fully
concentrate your mentation power [helped by knowledge, of course]
on this rather brief remark/thought of mine [taken out of original
context]:

"all I want is simply to get out as quickly as possible [with recorded
core dump, of course]... and with some recovery/cleanup-of-external-
resources done on some 'higher level' [rollback/restart-of-external-
transactions including]."

regards,
alexander.

Doug Harrison

unread,
Jul 26, 2002, 11:46:00 AM7/26/02
to
Alexander Terekhov wrote:

>
>Doug Harrison wrote:
>[...]
>> >> FWIW, I've been arguing this point for eight years, and I've
>> never >> heard a reasonable argument why catch(...) should catch
>> untranslated >> Win32 structured exceptions. >
>> >It should. And that's non-issue [implementation-defined unwinding
and
>> >"similar" problems {IMO} with C++ ex.specs. aside] if you catch
*ONLY*
>> >things you KNOW/REALLY want/need, AFAICS.
>>
>> Well, no. The point is that catch(...) catches non-C++ exceptions,
>> which destroys its usefulness for catching C++ exceptions.
>
>My, consider the following "mixture" of C/SEH and C++ exceptions:

Sorry, no. If you want me to look at a long piece of code, you should
take the time to explain it in a sentence or two. In any event, I
understand how SEH can be used in a C++ program, and it isn't relevant.
I thought my statements above and in the threads I cited were clear, but
let me try again. It should be possible to write a C++ program for
Windows without worrying about SEH. If catch(...) catches untranslated
SEs, and you use catch(...), this is impossible. I've given numerous
reasons why this is bad in the threads I linked to, and I expanded upon
one reason in the part of my last message you didn't respond to.

--
Doug Harrison
d...@mvps.org

Alexander Terekhov

unread,
Jul 26, 2002, 4:15:00 PM7/26/02
to

Doug Harrison wrote:
[...]

> >My, consider the following "mixture" of C/SEH and C++ exceptions:
>
> Sorry, no. If you want me to look at a long piece of code, you should
> take the time to explain it in a sentence or two.

Explanation [``in a sentence or two'']:

Moral #1: Don't use "unchecked" ["checked" via ex.specs; harmful
unwinding aside] catch(...)-idiom; use RAII/destructors instead.

Moral #2: Except that you really want "throw" ``INTERNAL_ERROR''
status/return code(s) on the poor face of your exception-less
callers, or perhaps, *re-throw* original exception [whatever it
is]... being extremely careful with respect to the danger of
replacing it with something ELSE -- thrown inside that silly
"(...)-handler" prior to "throw;".

> In any event, I understand how SEH can be used in a C++ program,

That's good.

> and it isn't relevant.

Uhmm. I'd say that nonintegrated SEs are simply "incomplete" C++
exceptions that can be intercepted in pure C++ {only} via catch(...)
if you really want/need it. I personally see NO reasons for doing
it in [pure] C++ to begin with, however. So, yeah, it's totally
irrelevant; indeed. ;-)

> I thought my statements above and in the threads I cited were clear,
> but let me try again. It should be possible to write a C++ program for

> Windows without worrying about SEH. If catch(...) catches untranslated

> SEs, and you use catch(...), this is impossible.

See #1/#2 above.

> I've given numerous
> reasons why this is bad in the threads I linked to, and I expanded
> upon one reason in the part of my last message you didn't respond to.

Well, you wrote:

: In your example, you threw a C++ exception when you shouldn't have,

Why so?

: and it could be caught by a std::exception handler, not just
catch(...).

Agreed. Catching using std::exception "handlers" is pretty much
the same as catching via catch(...)-thing; see #1/#2 above.

: There's no expectation of different behavior here.

Agreed.

: C++ exception handlers are supposed to catch C++ exceptions!

See <wink>-paragraph above.

: So while you may have a bug, I don't believe you have any reason
: to complain.

FULLY AGREED!!! ;-) Bugs should end up in "core dumped"/JIT-
debuggers/etc. as soon as possible [to prevent further damage, to begin
with]... even if "manifested" via *unexpected* {C++
and/or nonintegrated C/SEH, whatever} exceptions.

regards,
alexander.

Sergey P. Derevyago

unread,
Jul 29, 2002, 6:41:40 PM7/29/02
to
David Abrahams wrote:
> > > > 1) Never use catch(...), especially in portable code.
> > > How would you write uninitialized_fill without catch(...)?
> > IMHO RAII could really help here ("Who says writing exception-safe code is
> > trying?" :). For example
> Yes, but since you're the guy who's so concerned with efficiency, please try
> to get your compiler to generate code for the first version that's as fast
> as the code for the second version <wink>.
Well, let's compile the following code
-----------------------------------8<-----------------------------------
typedef int T;
typedef T* ForwardIterator;

void _Construct(void*, const T&);
void _Destroy(ForwardIterator, ForwardIterator);

class SomeHelper {
ForwardIterator first;
const ForwardIterator& curr;
bool isOk;
public:
SomeHelper(ForwardIterator f, const ForwardIterator& c) : first(f),
curr(c), isOk(0) {}

~SomeHelper() { if (!isOk) _Destroy(first, curr); }

void ok() { isOk=1; }
};

void uninitialized_fill1(ForwardIterator first, ForwardIterator last,


const T& x)
{
ForwardIterator curr=first;

SomeHelper sh(first, curr);


for ( ; curr!=last; ++curr)
_Construct(&*curr, x);
sh.ok();
}

void uninitialized_fill2(ForwardIterator first, ForwardIterator last,


const T& x)
{
ForwardIterator curr=first;
try {
for ( ; curr!=last; ++curr)
_Construct(&*curr, x);
}
catch (...) {
_Destroy(first, curr);
throw;
}
}

-----------------------------------8<-----------------------------------

g++ -O3 -S a.cpp

using gcc 3.1 (MinGW).

> The first version really does force the curr iterator onto the stack on
> every compiler I know of, whereas in the second version most compilers will
> keep it in a register (if it's a pointer).

Yes. Here are the main loops of both uninitialized_fill1 (on the left) and
uninitialized_fill2:
-----------------------------------8<-----------------------------------
pushl %eax | pushl %eax
pushl %eax | pushl %eax
movl -28(%ebp), %eax | movl 16(%ebp), %eax
pushl %esi | pushl %eax
pushl %eax | pushl %esi
call __Z10_ConstructPvRKi | call __Z10_ConstructPvRKi
movl -28(%ebp), %eax |
addl $16, %esp | addl $4, %esi
addl $4, %eax | addl $16, %esp
movl %eax, -28(%ebp) |
cmpl %ebx, %eax | cmpl %ebx, %esi
jne L7 | jne L29
-----------------------------------8<-----------------------------------
And we can see two additional commands:
movl -28(%ebp), %eax and movl %eax, -28(%ebp).
But this code was generated for "heavy" _Construct/_Destroy and these two
additional commands must not incur too much overhead (as compared to the
_Construct() call cost). So the prise is acceptable.

Now let's define the light versions of

void _Construct(void* ptr, const T& val) { *static_cast<T*>(ptr)=val; }
void _Destroy(ForwardIterator, ForwardIterator) {}

and explore the assembly:
-----------------------------------8<-----------------------------------
movl (%ebx), %eax | movl (%ecx), %eax
movl %eax, -4(%edx) | movl %eax, (%edx)
movl %edx, %eax |
cmpl %ecx, %eax | addl $4, %edx
leal 4(%edx), %edx | cmpl %ebx, %edx
jne L10 | jne L35
-----------------------------------8<-----------------------------------
Yes, gcc is sux:
1. Now values are constructed at [dx]-4 and
2. The pair
movl %edx, %eax
cmpl %ecx, %eax
could be replaced with plain
cmpl %ecx, %edx

So it seems like:
1. The RAII solution is much more pleasant to code and support.
2. Having a good optimizer:
- the involved overhead is quite acceptable for the "heavy"
_Construct/_Destroy pair and
- there is no overhead for the light one (not with gcc :( )


--
With all respect, Sergey. http://cpp3.virtualave.net/
mailto : ders at skeptik.net

0 new messages