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

Alexandrescu on error handling at ACCU conference 2002

11 views
Skip to first unread message

Alisdair Meredith

unread,
Apr 12, 2002, 11:57:24 AM4/12/02
to
[I am using the borland BCB5 compiler throughout, be interested to hear
how other compilers fare]

This post might make more sense if you were at Alexei's error handling
session at the ACCU conference, but a quick summary...
(Andrei, if you read this please correct anything I picked up wrong!)

The idea behind the class below is to add extra context information to
an exception that is propogating through my function.

The task is to catch and update exceptions without slowing the program
down by creating a try/catch block that typically isn't used. The
'clever' bit happens in the destructor of my ExceptionHandler class.

Andrei's idea was to catch exceptions in the destructor by testing
std::uncaught_exception, and then rethrowing within the destructor,
allowing us to insert a try/catch block only when an exception actually
exists. He then goes on to convert this exception into a different type
that supports extending the message, unlike std::exception where it is
fixed at construct-time.

As far as I can tell, BCB5 compiles and runs the following code, but the
exception carries on propogating automatically after my destructor
despite the catch blocks, so making the [commented out] rethrows not
only redundant, but the source of an abnormal termination. This makes
exception-conversion impossible.

My question is, is this correct behaviour? Should the following program
go to the exception handler in main with or without the rethrows?

Simple console app follows:


#include <ostream>
#include <string>
//---------------------------------------------------------------------
//template< char const*const COMMENT>
class ExceptionHandler
{
public:
ExceptionHandler( const std::string &sContext )
: m_sContext( sContext )
{
}

~ExceptionHandler( void )
{
if( std::uncaught_exception() )
{
try
{
throw;
}
catch( const std::exception &e )
{
std::cerr << m_sContext << ": "
<< e.what() << std::endl;
// throw;
}
catch(...)
{
// throw;
}
}
}

private:
const std::string m_sContext;
};
//---------------------------------------------------------------------
void TestFun( void )
{
ExceptionHandler guard( __FUNC__ );
throw std::runtime_error( "Hello World" );
std::cout << "Regular function exit" << std::endl;
}
//---------------------------------------------------------------------

#pragma argsused
int main(int argc, char* argv[])
{
try
{
TestFun();
std::cout << "No exceptions here" << std::endl;
}
catch( const std::exception & ) // I believe entry here is an error
{
std::cout << "Standard exception throw" << std::endl;
} // Swallow here
catch( ... )
{
std::cout << "Unknown exception throw" << std::endl;
} // Swallow here
return 0;
}

--
AlisdairM

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

Richard Corden

unread,
Apr 12, 2002, 9:07:08 PM4/12/02
to
Alisdair Meredith
<alisdair.no.spam.please.we're.britis...@uk.renaultf1.com> writes:

[...]

> Andrei's idea was to catch exceptions in the destructor by testing
> std::uncaught_exception, and then rethrowing within the destructor,
> allowing us to insert a try/catch block only when an exception actually
> exists. He then goes on to convert this exception into a different type
> that supports extending the message, unlike std::exception where it is
> fixed at construct-time.

15.1/6 says that calling 'throw' rethrows the exception being handled,
and 15.3/8 says than an exception is considered handled upon entry to
a handler (a catch block).

So, this says to me that the 'throw' in the try block will call
terminate as there is no exception being handled (15.1/8).

[...]

> My question is, is this correct behaviour? Should the following program
> go to the exception handler in main with or without the rethrows?

From the above, it should call terminate as throw is called in the dtor
with no exception currently being handled. This is the behaviour
of GCC.

[...]

Your example could be changed slightly to use function try blocks to
achieve something similar:

//---------------------------------------------------------------------
void TestFun( void )

try
{


throw std::runtime_error( "Hello World" );
std::cout << "Regular function exit" << std::endl;
}

catch (std::exception & e)
{
throw ExceptionHandler guard( __FUNC__, e );
}

This method has the disadvantage of extra typing. It does however
avoid the creation and destruction of objects which will only get used
under 'exceptional circumstances'. It also doesn't need to call and
check the value of std::uncaught_exception for every function. And
God forbid, you could even have two MACROS do the work! :)

Regards,

Richard


--
Richard Corden
To reply remove 's' from address

Roger Orr

unread,
Apr 12, 2002, 9:17:16 PM4/12/02
to
Alisdair Meredith wrote in message <3CB69B73...@uk.renaultf1.com>...

>[I am using the borland BCB5 compiler throughout, be interested to hear
>how other compilers fare]
>
>This post might make more sense if you were at Alexei's error handling
>session at the ACCU conference, but a quick summary...

Alas I missed that one :-)

[snip]

>Andrei's idea was to catch exceptions in the destructor by testing
>std::uncaught_exception, and then rethrowing within the destructor,
>allowing us to insert a try/catch block only when an exception actually
>exists.

If I understand this right then I don't think this is valid.

[except.throw] 15.1 Throwing an exception

p6 "A throwexpression with no operand rethrows the exception being
handled...."
p7 "The exception thrown is the one most recently caught and not
finished..."
p8 "If no exception is presently being handled, executing a throwexpression
with no operand calls terminate()..."

In the destructor you're not _handling_ the exception and so
std::uncaught_exception()
returns 'true'.

So by p8 I presume throwing with no operand will call terminate() at this
point.

FWIW vc.net calls terminate().

Roger Orr
--
MVP in C++ at www.brainbench.com

Mix

unread,
Apr 12, 2002, 9:20:04 PM4/12/02
to
In article <3CB69B73...@uk.renaultf1.com>, Alisdair Meredith wrote:
> ~ExceptionHandler( void )
> {
> if( std::uncaught_exception() )
> {
> try
> {
> throw;
> }

Doesn't 15.1.8 and 15.5.1.1 of ISO 14882:1998 explicitly state that this
throw results in a call to terminate()? You can't execute "throw;" (what the
standard calls a throw-expression) unless you are HANDLING an exception
(i.e. inside a catch {} block). You certainly can't do it from a destructor
during exception stack unwinding.

Am I misreading the standard?

Andrei Alexandrescu

unread,
Apr 13, 2002, 4:07:08 PM4/13/02
to
"Alisdair Meredith"
<alisdair.no.spam.please.we're.britis...@uk.renaultf1.com>
wrote in message news:3CB69B73...@uk.renaultf1.com...
[snip]

> Andrei's idea was to catch exceptions in the destructor by testing
> std::uncaught_exception, and then rethrowing within the destructor,
> allowing us to insert a try/catch block only when an exception
actually
> exists. He then goes on to convert this exception into a different
type
> that supports extending the message, unlike std::exception where it
is
> fixed at construct-time.
[snip]

Thanks for the note, Alisdair. Indeed, as the posts here that were
sent in the meantime, it seems like I was wrong about the
implementation of that idea.

However, this is not too worrisome because it relates to the
mechanics, not to the priciple.

Background (I will take some time to rehash things here, I believe it
is interesting):

In my talk, I conjectured that direct transport of information between
the throw location and the catch location is not enough for providing
adequate error information. This is because the exact context of
execution when the error appeared is relevant, and that context is
determined by the dynamic call stack - and not only by the throw
location and the catch location.

On the other hand, simply collecting a stack trace with function names
and argument values is not information that ought to be displayed to
the end user. So certain functions should add nicely formatted
contextual information. The trick is how to do that as easily as
possible.

The implementation idea (and here's a detail I glossed over in the
talk) is to create an automatic object that monitors
uncaught_exception(). The function must be monitored not only in the
destructor of ExceptionHandler (see the original post code), but also
in the constructor. The ExceptionHandler object detects that the scope
is exited through an exception iff upon construction
uncaught_exception() is false, and upon destruction
uncaught_exception() is true. A code example follows:

class ExceptionHandler
{
const std::string m_sContext;
const bool exceptionWasActive_;

public:
ExceptionHandler( const std::string &sContext )

: m_sContext( sContext ),
exceptionWasActive_(std::uncaught_exception())
{
}

~ExceptionHandler( void )
{
if( std::uncaught_exception() && !exceptionWasActive_ )
{
// Aha! An exception is being thrown from within this
scope!
... provide m_sContext as additional error information ...
}
else
{
// nothing to do
// either no exception is occuring
// or
// an exception was active already upon entrance
}
}
};

Now the question is how to add m_sContext to the currently throwing
exception. Here I was mistaken.

It is important that the principle (add salient context information to
the error as it propagates to upper layers) stays valid. Another
implementation is needed.

Fortunately, C++'s exception model allows only one exception to be
active at a time. It's a pity you can't get access to it at all times.
One solution that comes to mind is to accumulate the additional
information in a static structure (thread-local storage in a
multithreaded system). The static structure can be a stack of strings
(or, better yet, polymorphic objects).

In the uppermost catch block, you can do the "throw;" trick you are
referring to. There, you can combine whatever exception you've got
with the additional information you collected; build a relevant error
message; and clear the static data so that the next exceptional event
can fill it up again.

Thank you very much for pointing out this problem.


Andrei

Alexander Terekhov

unread,
Apr 15, 2002, 9:22:03 AM4/15/02
to
Andrei Alexandrescu wrote:
[...]

> Fortunately, C++'s exception model allows only one exception to be
> active at a time.

Are you sure? (well, AFAICT, it depends on your definition
of "exception to be active" term...)

> It's a pity you can't get access to it at all times.

Maybe (if someone could really show some usefulness w.r.t.
"get access to it" NOT catching it (providing REAL error
handling in the catch handler), IMHO).

> One solution that comes to mind is to accumulate the additional
> information in a static structure (thread-local storage in a
> multithreaded system). The static structure can be a stack of strings
> (or, better yet, polymorphic objects).

Excuse me, solution to what problem? Personally, I hardly
see how adding extra local context info (to the propagating
exception; which is *already* on the way to the PROPER handler;
well, "hopefully" ;-)) could help someone to provide a "better"
handling. On the other hand, if you are NOT going to provide
the error handling, everything you need to find out what was
"going on here" is/should be nicely preserved in a core-dump/
crash-dump/whatever program state emergency recording/dump
apparatus provided by your platform, I think. Or am I missing
something?

regards,
alexander.

Alisdair Meredith

unread,
Apr 16, 2002, 4:30:52 AM4/16/02
to
Alexander Terekhov wrote:

> Excuse me, solution to what problem? Personally, I hardly
> see how adding extra local context info (to the propagating
> exception; which is *already* on the way to the PROPER handler;
> well, "hopefully" ;-)) could help someone to provide a "better"
> handling. On the other hand, if you are NOT going to provide
> the error handling, everything you need to find out what was
> "going on here" is/should be nicely preserved in a core-dump/
> crash-dump/whatever program state emergency recording/dump
> apparatus provided by your platform, I think. Or am I missing
> something?

Yes, you missed the ACCU session :¬ )

If Alexei is speaking on this topic anywhere near you go see him, it
clarified a lot of issues for me! There is certainly more to it than
this little 'trick' we are discussing here.

The basic problem is not handling bugs or programmer faults, which may
well come down to core dumps. The idea is to present the user of your
appliation with some more meaningful information, so 'context' in this
case is usually adding some formatted string for the user.

As such, you don't want to interfere with the propogation of the
exception. Ideally, we don't want to catch it, simply append a little
more info. Ideally we don't even want to pay the cost of formatting
this info unless an exception is actually propogating. Hence all the
testing for uncaught_exception.

If the throw/catch trick is illegal, then I can see no alternative to
storing the context data entirely external to the exception itself.
Given each thread of execution will have its own stack to unwind, it
makes sense this must be thread-local storage of some kind as Andrei
suggests. I guess the trick will be to preallocate a buffer for error
context so that there is no need to allocated further memory during the
unwind, and so risk throwing a second exception and calling terminate().

--
AlisdairM

Roger Orr

unread,
Apr 16, 2002, 4:38:41 AM4/16/02
to
Andrei Alexandrescu wrote in message ...
[snip]

>Indeed, as the posts here that were
>sent in the meantime, it seems like I was wrong about the
>implementation of that idea.
[snip]

OTOH perhaps it would be worth seeing if some way of accessing the
current exception could be added for C++0x.

Any good suggestions for a proposal?

Roger Orr
--
MVP in C++ at www.brainbench.com

Hillel Y. Sims

unread,
Apr 16, 2002, 2:50:53 PM4/16/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3CBA86A3...@web.de...

> Andrei Alexandrescu wrote:
> [...]
> > Fortunately, C++'s exception model allows only one exception to be
> > active at a time.
>
> Are you sure? (well, AFAICT, it depends on your definition
> of "exception to be active" term...)
>

yes -> you can't access the current exception correctly inside a destructor
when (std::uncaught_exception() == true) (I tried this on my platform too,
and it didn't work very well *crash*), and once you enter a catch() block
where you can legally access it, it is already considered finalized (/not/
active) and will not be rethrown without an explicit throw; .. or if you
throw SomethingElse(); that's really throwing a new exception and there is
really only one exception outstanding at all times. If something causes a
new exception to be thrown at any point while another is still active
(std::uncaught_exception() == true -- either in a destructor or during
internal runtime copy of exception object), std::terminate() is going
(supposed) to be called.

> Excuse me, solution to what problem? Personally, I hardly
> see how adding extra local context info (to the propagating
> exception; which is *already* on the way to the PROPER handler;
> well, "hopefully" ;-)) could help someone to provide a "better"
> handling. On the other hand, if you are NOT going to provide
> the error handling, everything you need to find out what was
> "going on here" is/should be nicely preserved in a core-dump/
> crash-dump/whatever program state emergency recording/dump
> apparatus provided by your platform, I think. Or am I missing
> something?
>

Well catch() handlers can throw off the state of the core dump from the
actual state the process was in at the moment the exception was thrown,
because they cause stack unwinding:

void f()
{
throw UnhandledExc();
}

void g()
{
try {
f();
}
catch (NotEnough&) { ... };
}

void h()
{
// some non-automatically protected stack-guarded stuff
..
try {
g();
}
catch (...) {
// restore prior state to avoid violating basic exception safety
throw;
}
}

int main()
{
h();
}

Now, without philosophical argument about why this may be an unfortunate way
to write some code, the deepest stack frame that will probably exist in your
core dump / stack trace will be pointing at the "throw;" point inside the
catch(...) block in h(), even though the exception was unhandled and raised
all the way up in f() and caused the application to terminate (but note, not
immediately, it did some catch(...) stuff first)

This is, of course, completely conforming behavior (and in fact, all
platforms must correctly run the catch(...) block above regardless of how
else they handle stack unwinding during unhandled exception), and therefore
it is reasonable to wish to have a portable mechanism to add full context
information to exceptions, such that some reasonable amount of call stack
information can be obtained.

Unfortunately, I cannot help you much here, unless you are on OpenVMS :-) I
have done some work on my platform to accomplish this technique (fully
automatic non-intrusive context logging for exceptions, even with
catch(...)/throw) through the OS native stack-trace handler facility (the
way the runtime itself would have to implement this functionality, if it
were to do so). It works fairly well, but introduces a fairly expensive
overhead on throwing exceptions (which is already much more expensive than a
regular function call), as we must now also log the stack trace at every
originating throw point. However, since exceptions are really intended to be
thrown fairly infrequently (not 50000 times in a loop...) and not in
time-sensitive situations anyway, then it seems mostly a workable solution -
if highly non-portable :-)

hys
--
Hillel Y. Sims
hsims AT factset.com

Nicola Musatti

unread,
Apr 16, 2002, 7:13:00 PM4/16/02
to
If I understood the objections (and the standard) correctly, the "throw;
from a try block" should work if performed in a call sequence
originating in a catch block.

If this is the case this technique can still be applied to separate the
preparation of local context information from the mechanics of
piggybacking. We could have something like:

void handleException(const string & context) {
try {
throw;
}
catch (MyExceptionBase & e) {
// tack context on e


}
catch (std::exception & e) {

throw MyExceptionWrapper(e,context);
catch (...) {
throw MyConcreteException(context);
}
}

Than those functions that need to provide the context information can be
written as:

void f() {
try {
// perform task
}
catch (...) {
// prepare context
handleException(context);
}
}

Not as clean or as safe as your guard class would have been, but still
better than having to repeat the same code in different handlers.

Cheers,
Nicola Musatti

Richard Corden

unread,
Apr 16, 2002, 7:15:31 PM4/16/02
to

Hi,

How would context information for constructors of classes be added?
If a member in the intialisation list of a class throws, the context
information object will not be constructed:

[...]

class A
{
public:
A ()
: m_b () // throws
{
// This is not constructed as the function body is not executed.
ExceptionHandler guard( __FUNC__ );
}

A (int)
try
: m_b () // throws
{}
catch ( std :: exception & e)
{
throw ExceptionHandler ( __FUNC__, e.what () ); // adds context
}

B m_b;
};

You could avoid this by adding an ExceptionHandler as a member of the
class, but not only would you need to insure that it was the first
member object of the class, you'd also have this extra information in
every instance of the class for your project.

Alexander Terekhov

unread,
Apr 16, 2002, 7:27:54 PM4/16/02
to

Alisdair Meredith wrote:
[...]

> The basic problem is not handling bugs or programmer faults, which may
> well come down to core dumps. The idea is to present the user of your
> appliation with some more meaningful information, so 'context' in this
> case is usually adding some formatted string for the user.

Do you have an example? And, just to make it a bit clear, with "user",
I do NOT mean the change/service team engineers -- folks who just love
traces, logs, dumps, etc.

regards,
alexander.

Alexander Terekhov

unread,
Apr 17, 2002, 4:12:25 AM4/17/02
to

Alexander Terekhov wrote:
>
> Andrei Alexandrescu wrote:
> [...]
> > Fortunately, C++'s exception model allows only one exception to be
> > active at a time.
>
> Are you sure? (well, AFAICT, it depends on your definition
> of "exception to be active" term...)

A friend of mine asked me privately to clarify
this "Are you sure?" bit. I think that it will
be a not entirely bad idea if I do it here...

lnxmuell:/usr/terekhov # g++ -o e e.cpp
lnxmuell:/usr/terekhov # ./e
throw 0
throw 1
throw 2
throw 3
throw 4
throw 5
throw 6
throw 7
throw 8
throw 9
Okay... ENOUGH active exceptions! ;-)
caught 9
caught 8
caught 7
caught 6
caught 5
caught 4
caught 3
caught 2
caught 1
caught 0
lnxmuell:/usr/terekhov # cat e.cpp

#include <iostream>
using namespace std;

int ex_count = 0;

int foo();

struct object {

~object() { foo(); }

};

int foo()
{

int ex = ex_count++;

try {

if ( ex < 10 ) {

// Nah, I want MORE active exceptions ;-)
object obj;

cout << "throw " << ex << endl;

throw ex;

}
else {

cout << "Okay... ENOUGH active exceptions! ;-)" << endl;

}

}
catch( int ex_caught ) {

cout << "caught " << ex_caught << endl;

}

return ex;

}

int main()
{
return foo();
}

lnxmuell:/usr/terekhov #

Alexander Terekhov

unread,
Apr 17, 2002, 4:13:50 AM4/17/02
to

"Hillel Y. Sims" wrote:
[...]

> If something causes a
> new exception to be thrown at any point while another is still active
> (std::uncaught_exception() == true -- either in a destructor or during
> internal runtime copy of exception object), std::terminate() is going
> (supposed) to be called.

Apart from "internal runtime copy of exception object", that's
just WRONG (unless I've totally screwed up things in "e.cpp"
I've recently posted here ;-)).

AFAICT, std::uncaught_exception() is a pretty useless function.
My opinion/view on this:

http://groups.google.com/groups?as_umsgid=3CB59C36.B4C0008A%40web.de
(see "Also, since AFAIK, you have a lot of expertise w.r.t.
std::uncaught_exception() function..." bit)

Hillel, frankly, WHY THE HELL DO YOU NEED/USE THAT "catch/re-throw"
thing!?

My opinion/view on this:

http://groups.google.com/groups?as_umsgid=3C9B85C2.39936A4B%40web.de
(see "Actually, I don't think that there is much sense to
catch/re-throw anything, in general..." and "Also, if someone
really need it, I think that C++ could provide something like
'const T* unhandled_exception< T >()'" bits)

regards,
alexander.

Hillel Y. Sims

unread,
Apr 17, 2002, 11:34:35 AM4/17/02
to

"Nicola Musatti" <obje...@divalsim.it> wrote in message
news:3CBC15F9...@divalsim.it...

> void handleException(const string & context) {
> try {
> throw;
> }
> catch (MyExceptionBase & e) {
> // tack context on e
> }
> catch (std::exception & e) {
> throw MyExceptionWrapper(e,context);
> catch (...) {
> throw MyConcreteException(context);
> }
> }
>

This would almost work, but in the last catch(...) you are discarding the
most important context of all -- the actual exception! It's not correct to
rethrow a different type of exception from catch(...) because you don't know
what the original type was (and it may have been important). You can
theoretically wrap anything inherited from std::exception, because then at
least you can use what() and dynamic_cast, though that would likely make
things fairly difficult too. The best solution would be just to use
MyExceptionBase (inherited from std::exception) like your first catch block
which you can add context, and inherit all application exceptions from
MyExceptionBase (though you might also need to rethrow it here after adding
'context' info)

hys

--
Hillel Y. Sims
hsims AT factset.com

Andrei Alexandrescu

unread,
Apr 17, 2002, 7:31:56 PM4/17/02
to
> How would context information for constructors of classes be added?
[snip]

> You could avoid this by adding an ExceptionHandler as a member of
the
> class, but not only would you need to insure that it was the first
> member object of the class, you'd also have this extra information
in
> every instance of the class for your project.

I think the best use of such "context info provider" objects is as
standalone automatic objects that are put in strategic functions, not
as members of larger objects.

I am not really sure, but my current belief is that in error handling,
objects don't matter; the excecution flow matters. An error transcends
multiple objects; conversely, a single object can be "traversed" by
many errors.


Andrei

Andrei Alexandrescu

unread,
Apr 17, 2002, 7:32:39 PM4/17/02
to
"Alexander Terekhov" <tere...@web.de> wrote in message
news:3CBC82C9...@web.de...

> AFAICT, std::uncaught_exception() is a pretty useless function.
> My opinion/view on this:
>
> http://groups.google.com/groups?as_umsgid=3CB59C36.B4C0008A%40web.de
> (see "Also, since AFAIK, you have a lot of expertise w.r.t.
> std::uncaught_exception() function..." bit)

It is an extremely useful function for error handling.

I realize that by this I also contradict Herb, because he also wrote,
with examples, that uncaught_exception() is not really useful. Herb
makes an excellent point: you need a sort of a stack of bools, not a
bool, to get information on what's going on.

Even in its rudimentary form, std::uncaught_exception() is useful: if
the value of std::uncaught_exception() upon constucting an automatic
object is different from the value of std::uncaught_exception() upon
destroying that object, that is a sign that the scope containing that
object is being exited through an exception. The object itself can add
relevant information about the execution context to the error message
that might ultimately be displayed to the end user.


Andrei

Alisdair Meredith

unread,
Apr 18, 2002, 6:47:36 AM4/18/02
to
Alexander Terekhov wrote:

> Do you have an example? And, just to make it a bit clear, with "user",
> I do NOT mean the change/service team engineers -- folks who just love
> traces, logs, dumps, etc.

Well, I could just give the examples Alexei gave at the session, but I
already feel I am trading too much on another's riches <g>

He did indeed make the point that a stack dump is not terribly useful to
the end user, but neither is the text 'operation failed'. This part of
the session was looking for a good way to fill that gap.

--
AlisdairM

Hillel Y. Sims

unread,
Apr 18, 2002, 9:52:35 AM4/18/02
to
If you can't touch the current exception during stack unwinding, you can
still take advantage of that uncaught_exception() state-change (is it even
really possible that it could be true on ctor and false on dtor? I think
that would mean the exception were already handled, so nothing further to do
anyhow?) to do some other sort of context logging / notification / whatever.
It might even be in a ScopeGuard-like fashion where you might pass a
notification callback to be alerted on block exit due to exception.

{
ExceptionGuard e = MakeExceptionGuard(*this, &ThisType::ExcCallback);
// blah blah
// maybe throw
}

ExceptionGuard would only call ExcCallback() if an exception causes it to be
destructed. But it would not be able to know what type of exception is
currently propagating. (Perhaps being able to access the current exception
without finalizing it would be a useful addition to the language?)

Would this be useful for anything?

hys

"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:a9k4co$3ujim$1...@ID-14036.news.dfncis.de...


> > How would context information for constructors of classes be added?
> [snip]
> > You could avoid this by adding an ExceptionHandler as a member of
> the
> > class, but not only would you need to insure that it was the first
> > member object of the class, you'd also have this extra information
> in
> > every instance of the class for your project.
>
> I think the best use of such "context info provider" objects is as
> standalone automatic objects that are put in strategic functions, not
> as members of larger objects.
>
> I am not really sure, but my current belief is that in error handling,
> objects don't matter; the excecution flow matters. An error transcends
> multiple objects; conversely, a single object can be "traversed" by
> many errors.
>

--


Hillel Y. Sims
hsims AT factset.com

Hillel Y. Sims

unread,
Apr 18, 2002, 11:17:11 AM4/18/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message
news:3CBC82C9...@web.de...

>
> "Hillel Y. Sims" wrote:
> [...]
> > If something causes a
> > new exception to be thrown at any point while another is still active
> > (std::uncaught_exception() == true -- either in a destructor or during
> > internal runtime copy of exception object), std::terminate() is going
> > (supposed) to be called.
>
> Apart from "internal runtime copy of exception object", that's
> just WRONG (unless I've totally screwed up things in "e.cpp"
> I've recently posted here ;-)).
>

ok sorry about that..

if something causes a new exception to be thrown and /escape the current
scope/ during already active exception handling (when
std::uncaught_exception() == true), std::terminate() will be called.

your example demonstrates recursive exception handling of 9 active
exceptions, but none of them ever actually escape their current scope, as
the catch block deactivates each innermost recursive exception on the unwind
from the recursive loop.

> > Well catch() handlers can throw off the state of the core dump from the
> > actual state the process was in at the moment the exception was thrown,
> > because they cause stack unwinding:
> >
> > void f()
> > {
> > throw UnhandledExc();
> > }
> >
> > void g()
> > {
> > try {
> > f();
> > }
> > catch (NotEnough&) { ... };
> > }
> >
> > void h()
> > {
> > // some non-automatically protected stack-guarded stuff
> > ..
> > try {
> > g();
> > }
> > catch (...) {
> > // restore prior state to avoid violating basic exception safety
> > throw;
>
> Hillel, frankly, WHY THE HELL DO YOU NEED/USE THAT "catch/re-throw"
> thing!?

That is partially the point of the example. I was trying to demonstrate a
concept, that catch/rethrow skews core dump stack trace of unhandled
exception. It demonstrates further the usefulness of RAII/ScopeGuard-style
approach to cleanup vs using somewhat typical catch/rethrow blocks (because
you can get a clean stack trace and then maybe don't need manual context
logging)

hys

--
Hillel Y. Sims
hsims AT factset.com

Hillel Y. Sims

unread,
Apr 18, 2002, 11:17:54 AM4/18/02
to

"Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
news:a9k43g$3o73k$1...@ID-14036.news.dfncis.de...

>
> It is an extremely useful function for error handling.
>
> I realize that by this I also contradict Herb, because he also wrote,
> with examples, that uncaught_exception() is not really useful. Herb
> makes an excellent point: you need a sort of a stack of bools, not a
> bool, to get information on what's going on.

I think you are both talking about it in a different context. He shows that
it is useless/bad in destructors to attempt to determine whether it is safe
to throw an exception.

T::~T()
{
if (std::uncaught_exception()) {
// cannot throw
}
else {
// can throw(?)
}
}

This is bad because you really cannot throw safely even in the else block,
since it still breaks the safety of something like T t[5]; (cannot
deterministically destruct all elements on block exit).

You are recommending use of it in a different manner, for which it might
actually be useful, except for the limitation that one cannot actuallly
access the currently active exception at the point that uncaught_exception()
is true anyhow.

>
> Even in its rudimentary form, std::uncaught_exception() is useful: if
> the value of std::uncaught_exception() upon constucting an automatic
> object is different from the value of std::uncaught_exception() upon
> destroying that object, that is a sign that the scope containing that
> object is being exited through an exception. The object itself can add
> relevant information about the execution context to the error message
> that might ultimately be displayed to the end user.

But here there would be little additional useful context information that
can be gotten, since the exception object is inaccessible (if it were
accessible, I think there might be more utility here). Other than the
concrete type and any data contained within the exception object, the flow
of control is already known implicitly to the program by its inherent
structure; I don't think anything more really useful about that can be
obtained at the point of this object destructor being activated (except for
debugging info, but you'd only be able to log a stack trace and not the type
of exception anyhow).

void a()
{


// blah blah
// maybe throw
}

void b()
{
a();
// if exit via exception, I may not know what type
// of exception, but I know that it came from a().
// use try/catch block HERE if need to know that
// exception came from a()
}

void c()
{
try {
b();
}
catch (MyExcType& e) {
// I know exception came from within b() subsystem,
// and I know what type and can get whatever data out
}
}

If the error handling code is structured properly, it shouldn't matter at
this point in c() whether the exception came from b() directly or indirectly
via a(). If it's necessary to know that an error came directly from a(),
then the call to a() in b() should have been protected by a try/catch block
too. Otherwise, c() only needs to know that something happened when it
called b(). Anything more than that, eg if c() really needs to know that a()
threw the exception, seems like it would be overly complicated to me; proper
layering of functionality should obtain the same results much cleaner. (But
for debugging purposes, I could see some usefulness here for doing couts or
calling some notification function or something.)

BTW, if you haven't already seen me say it, I'm a really big fan of
ScopeGuard. Thanks :-)

hys

--
Hillel Y. Sims
hsims AT factset.com

Nicola Musatti

unread,
Apr 18, 2002, 11:24:54 AM4/18/02
to

"Hillel Y. Sims" wrote:
[...]

> This would almost work, but in the last catch(...) you are discarding the
> most important context of all -- the actual exception! It's not correct to
> rethrow a different type of exception from catch(...) because you don't know
> what the original type was (and it may have been important). You can
> theoretically wrap anything inherited from std::exception, because then at
> least you can use what() and dynamic_cast, though that would likely make
> things fairly difficult too. The best solution would be just to use
> MyExceptionBase (inherited from std::exception) like your first catch block
> which you can add context, and inherit all application exceptions from
> MyExceptionBase (though you might also need to rethrow it here after adding
> 'context' info)

Actually I discard the original exception on purpose, but I should have
explained. I'm aware there is a trade off: I don't know the exception,
so I don't now how important the information it carries may be. Either I
let it pass hoping that higher level code might know about it, or I
discard it and provide at least the information I'm currently able to
provide.

In the setting of a project wide exception handling strategy the escape
of unknown exceptions should never take place, so the only strategies
that appear reasonable to me are either to abort execution or to throw a
new, known exception that signals the catching of an unknown one.

Cheers,
Nicola Musatti

Nicola Musatti

unread,
Apr 18, 2002, 4:32:34 PM4/18/02
to

Andrei Alexandrescu wrote:
[...]


> I am not really sure, but my current belief is that in error handling,
> objects don't matter; the excecution flow matters. An error transcends
> multiple objects; conversely, a single object can be "traversed" by
> many errors.

I feel the same. If it weren't for RAII the current exception handling
paradigm would appear to fit better a procedural approach than an object
oriented one.

Cheers,
Nicola Musatti

Hendrik Schober

unread,
Apr 19, 2002, 9:34:11 AM4/19/02
to
"Alexander Terekhov" <tere...@web.de> wrote:
> [...]
> Do you have an example? [...]

"Could not process macro. Reason:
Could not open file 'xyz.macro'. Reason:
Not enough memory."

Here, "not enough memory" was the first thing
to report, but it would probably have been
less helpful without the added information
what the program was trying to do.

(Actually, this is almost a real world example.
A customer of ours used this to find out that
'xyz.mac' was a 4GB binary file.)

> regards,
> alexander.

Schobi

--
Spam...@gmx.de is never read
I'm hschober at gmx dot de

Alexander Terekhov

unread,
Apr 19, 2002, 9:40:50 AM4/19/02
to

Andrei Alexandrescu wrote:
>
> "Alexander Terekhov" <tere...@web.de> wrote in message
> news:3CBC82C9...@web.de...
> > AFAICT, std::uncaught_exception() is a pretty useless function.
> > My opinion/view on this:
> >
> > http://groups.google.com/groups?as_umsgid=3CB59C36.B4C0008A%40web.de
> > (see "Also, since AFAIK, you have a lot of expertise w.r.t.
> > std::uncaught_exception() function..." bit)
>
> It is an extremely useful function for error handling.
>
> I realize that by this I also contradict Herb, because he also wrote,
> with examples, that uncaught_exception() is not really useful. Herb
> makes an excellent point: you need a sort of a stack of bools, not a
> bool, to get information on what's going on.
>
> Even in its rudimentary form, std::uncaught_exception() is useful: if
> the value of std::uncaught_exception() upon constucting an automatic
> object is different from the value of std::uncaught_exception() upon
> destroying that object, that is a sign that the scope containing that
> object is being exited through an exception.

The standard says:

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

Now, tell me please, is it really needed to have
some degree in rocket science to come to the idea
of something along the lines of:

"bool unwinding< T >(T*)" (or macro/whatever)

that would basically tell whether an object
(identified via "this" or some other ptr) has
entered destruction phase, and, if yes, whether
it's due to 'stack-unwinding' on exception
propagation?! Or am I just missing something
here?

Another "improvement", as it seems to me,
could be that "bool expected_exception<T>()"
thing -- it would basically tell whether
throwing T will just result in either
unexpected() or terminate() altogether.
Hmm. What am I missing *here* (archaic/silly
exception impls. without search-only capability
in the dynamic context aside, please)?.

Well, also, I guess that I would have NO
problems with something along the lines of:

"T* propagating_exception_ptr<T>()" (and/or
the ref.one -- throwing something if "not
found" instead of returning null; actually
I'd prefer *const*, but see below)

either (to perform some exception type and
info *sensitive* "fixup" for subsequent
operations/retries NOT catching/re-throwing
exceptions -- that's IMHO just silly; though
I don't have any really good examples on such
"fixup" at the moment)...

But as for "attaching/adding" something to the
propagating exception (communicating that extra
info to the REAL catch handler (which, in my school
of thought, should either do error RECOVERY with
subsequent retries or some EXPECTED/KNOWN ERROR
reporting prior to graceful termination):

> The object itself can add
> relevant information about the execution context to the error message
> that might ultimately be displayed to the end user.

Well, again... Do you have an example? Please.

regards,
alexander.

Alexander Terekhov

unread,
Apr 19, 2002, 11:50:07 AM4/19/02
to

"Hillel Y. Sims" wrote:
[...]
> if something causes a new exception to be thrown and /escape the current
> scope/ during already active exception handling (when
> std::uncaught_exception() == true), std::terminate() will be called.

Right... in *C++*. But in Java, for example/AFAIK, a new one will just
"replace" the "old" one. I like C++ (terminate() is much more reasonable
resolution, in my view).

> your example demonstrates recursive exception handling of 9 active

Nah, *10*!! ;-)

> exceptions, but none of them ever actually escape their current scope, as
> the catch block deactivates each innermost recursive exception on the unwind
> from the recursive loop.

Yep (recursion was used just to build "nested scopes of unwinding"
with less code).

[...]


> > > // some non-automatically protected stack-guarded stuff
> > > ..
> > > try {
> > > g();
> > > }
> > > catch (...) {
> > > // restore prior state to avoid violating basic exception safety
> > > throw;
> >
> > Hillel, frankly, WHY THE HELL DO YOU NEED/USE THAT "catch/re-throw"
> > thing!?
>
> That is partially the point of the example. I was trying to demonstrate a
> concept, that catch/rethrow skews core dump stack trace of unhandled
> exception.

Yup.

> It demonstrates further the usefulness of RAII/ScopeGuard-style
> approach to cleanup vs using somewhat typical catch/rethrow blocks (because
> you can get a clean stack trace and then maybe don't need manual context
> logging)

Why "maybe"? Just do NOT use that silly catch/re-throw trick
(do NOT provoke *needless*, well, actually HARMFUL unwinding).

That is why I wrote:

http://groups.google.com/groups?as_umsgid=3C9B85C2.39936A4B%40web.de

"Actually, I don't think that there is much sense to

catch/re-throw anything, in general... Why should the
local context cleanup/fixup be depended on the actual
nature of propagating exception? I think that, instead,
everything should be done in local objects destructors,
and/or perhaps in some "better" version of "finally"
clauses (I mean full access to local context but
templatized, if that would/could be possible):

http://groups.google.com/groups?threadm=3C73AB86.99B8CBE0%40web.de

....

Also, if someone really need it, I think that C++ could
provide something like 'const T* unhandled_exception< T >()'"

^^^^^^^^^^^^^^^^^^^

a better name is probably "propagating_exception", I also
mentioned it in my previous post here (in this thread).

"to allow exception-type sensitive local cleanup/fixup
WITHOUT that silly "catch/re-throw" technique, IMHO.
(in addition to "fixing" things like unwinding on ES
violation and function-try-block "handlers" of
c-tors/d-tors... unless I am missing something BIG,
which somehow would explain to me the USEFULNESS
and RATIONALE behind these "ideas").

regards,
alexander.

Anthony Williams

unread,
Apr 20, 2002, 8:27:45 AM4/20/02
to
"Hillel Y. Sims" <use...@phatbasset.com> wrote in message news:<k8qv8.13991$Jl.43...@news02.optonline.net>...

> "Andrei Alexandrescu" <andre...@hotmail.com> wrote in message
> news:a9k43g$3o73k$1...@ID-14036.news.dfncis.de...
> > Even in its rudimentary form, std::uncaught_exception() is useful: if
> > the value of std::uncaught_exception() upon constucting an automatic
> > object is different from the value of std::uncaught_exception() upon
> > destroying that object, that is a sign that the scope containing that
> > object is being exited through an exception. The object itself can add
> > relevant information about the execution context to the error message
> > that might ultimately be displayed to the end user.
>
> But here there would be little additional useful context information that
> can be gotten, since the exception object is inaccessible (if it were
> accessible, I think there might be more utility here). Other than the
> concrete type and any data contained within the exception object, the flow
> of control is already known implicitly to the program by its inherent
> structure; I don't think anything more really useful about that can be
> obtained at the point of this object destructor being activated (except for
> debugging info, but you'd only be able to log a stack trace and not the type
> of exception anyhow).

You could add data to a separate stack, which was consulted by the
exception handler.

Hillel Y. Sims

unread,
Apr 20, 2002, 9:39:22 AM4/20/02
to

"Alexander Terekhov" <tere...@web.de> wrote in message

news:3CBFE12B...@web.de...


>
> "Hillel Y. Sims" wrote:
> [...]
>

> > your example demonstrates recursive exception handling of 9 active
>
> Nah, *10*!! ;-)

eh, I'm not very good at counting... ;-)

> I think that, instead,
> everything should be done in local objects destructors,
> and/or perhaps in some "better" version of "finally"
> clauses (I mean full access to local context but
> templatized, if that would/could be possible):
>

Have you seen Andrei & Petru's ScopeGuard.h? ON_BLOCK_EXIT == templatized
generic local object whose dtor provides 'finally' semantics for current
scope. I'm convinced it's pretty much a "better" 'finally' for C++ (more
flexibility than typical 'finally'). (I pasted a link to the CUJ online
article which also has a link to the source the other day, you can
google-search for it.)

void func()
{
char* p = static_cast<char*>(malloc(...));
if (p != 0) {
ON_BLOCK_EXIT(free, p);
....
// tons of hairy multiple-exit-path (maybe return or throw) stuff
here
....
}
// p is automatically freed!
}

(example for those times when you really need to use raw malloc'd memory...)

> violation and function-try-block "handlers" of
> c-tors/d-tors... unless I am missing something BIG,

Herb Sutter provides an excellent and thorough explanation for why
function-try blocks of ctors are pretty much useless (and how to get the
desired effect in a more meaningful way via containment/smart-ptrs), and for
any other type of function just redundant, in _More Exceptional C++_.

hys

--
Hillel Y. Sims hsims AT factset.com

Lead Software Engineer FactSet Research Systems

Hillel Y. Sims

unread,
Apr 21, 2002, 10:50:53 AM4/21/02
to
What would you really put on that stack, since you still won't be able to
know what kind of exception happened (can't even call e.what() or anything)?
Without being able to do anything with the exception itself, I think it
might only be helpful for some debugging, but just a little.

"Anthony Williams" <anthon...@yahoo.com> wrote in message
news:e045bea7.02041...@posting.google.com...


> > But here there would be little additional useful context information
that
> > can be gotten, since the exception object is inaccessible (if it were
> > accessible, I think there might be more utility here). Other than the
> > concrete type and any data contained within the exception object, the
flow
> > of control is already known implicitly to the program by its inherent
> > structure; I don't think anything more really useful about that can be
> > obtained at the point of this object destructor being activated (except
for
> > debugging info, but you'd only be able to log a stack trace and not the
type
> > of exception anyhow).
>
> You could add data to a separate stack, which was consulted by the
> exception handler.

--
Hillel Y. Sims
hsims AT factset.com

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

Andrei Alexandrescu

unread,
Apr 21, 2002, 11:03:51 AM4/21/02
to
"Anthony Williams" <anthon...@yahoo.com> wrote in message
> You could add data to a separate stack, which was consulted by the
> exception handler.

Quite so. It would have been very nice to hold the stack right inside
the exception object being thrown, so you don't have to mess with
thread local storage. But that's a minor disadvantage. I think this
solution is entirely acceptable, and adds great value to an
application's error handling strategy.


Andrei

Alexander Terekhov

unread,
Apr 21, 2002, 11:11:18 AM4/21/02
to

"Hillel Y. Sims" wrote:
[...]
> > I think that, instead,
> > everything should be done in local objects destructors,
> > and/or perhaps in some "better" version of "finally"
> > clauses (I mean full access to local context but
> > templatized, if that would/could be possible):
> >
>
> Have you seen Andrei & Petru's ScopeGuard.h?

Yes. It's fine.

> ON_BLOCK_EXIT == templatized
> generic local object whose dtor provides 'finally' semantics for current
> scope. I'm convinced it's pretty much a "better" 'finally' for C++ (more
> flexibility than typical 'finally').

Well, I mean basically something along the lines of:
(but with a constructor too ;-))

http://groups.google.com/groups?as_umsgid=3A9E5923.29E877B7%40dresdner-bank.com
(see "- Create a local instance with a destructor: ....")

[...]


> > violation and function-try-block "handlers" of
> > c-tors/d-tors... unless I am missing something BIG,
>
> Herb Sutter provides an excellent and thorough explanation for why
> function-try blocks of ctors are pretty much useless

That's good (seems that I'm NOT "missing something BIG", then ;-)).

> (and how to get the
> desired effect in a more meaningful way via containment/smart-ptrs), and for
> any other type of function just redundant, in _More Exceptional C++_.

Don't have this "More" one yet (and my SF-only season is NOT over yet
;-)).
Added to the "read-this" list. Thanks. Heck, what GotW is that, BTW?

regards,
alexander.

Andrei Alexandrescu

unread,
Apr 21, 2002, 5:33:07 PM4/21/02
to
"Hillel Y. Sims" <use...@phatbasset.com> wrote in message
news:81ew8.8002$7e5.2...@news02.optonline.net...

> What would you really put on that stack, since you still won't be
able to
> know what kind of exception happened (can't even call e.what() or
anything)?
> Without being able to do anything with the exception itself, I think
it
> might only be helpful for some debugging, but just a little.

At a minimum, you'd put strings. When you do catch the exception, you
have access to the exception itself and to the additional information
as well.


Andrei

Igor Ivanov

unread,
Apr 22, 2002, 3:49:28 AM4/22/02
to
"Hillel Y. Sims" <use...@phatbasset.com> wrote in message news:<%w4w8.3347$7e5.1...@news02.optonline.net>...
[...]

> Have you seen Andrei & Petru's ScopeGuard.h? ON_BLOCK_EXIT == templatized
> generic local object whose dtor provides 'finally' semantics for current
> scope. I'm convinced it's pretty much a "better" 'finally' for C++ (more
> flexibility than typical 'finally').

try/ finally is unbeatable for its generality because the finally
clause could contain any kind of code - several statements, macros -
whatever. BTW they don't claim that their ScopeGuard solves all
problems of resource protection. I am not sure I understand what you
mean by "more flexibility".

Igor

Nicola Musatti

unread,
Apr 22, 2002, 10:05:19 AM4/22/02
to

"Hillel Y. Sims" wrote:
>
> What would you really put on that stack, since you still won't be able to
> know what kind of exception happened (can't even call e.what() or anything)?
> Without being able to do anything with the exception itself, I think it
> might only be helpful for some debugging, but just a little.

Still, you do know that the sequence of operations contained in the try
block failed; in a well layered program this should refer to one
conceptual operation within the current layer and you can provide the
user with information about that. This information is usually neither
available at the throw point nor at the user interface.

Cheers,
Nicola Musatti

Alexander Terekhov

unread,
Apr 22, 2002, 10:11:18 AM4/22/02
to

Hendrik Schober wrote:
>
> "Alexander Terekhov" <tere...@web.de> wrote:
> > [...]
> > Do you have an example? [...]
>
> "Could not process macro. Reason:
> Could not open file 'xyz.macro'. Reason:
> Not enough memory."
>
> Here, "not enough memory" was the first thing
> to report, but it would probably have been
> less helpful without the added information
> what the program was trying to do.
>
> (Actually, this is almost a real world example.
> A customer of ours used this to find out that
> 'xyz.mac' was a 4GB binary file.)

Out-of-memory aside for a moment, what's wrong with

something along the lines of:

/* ....invoke operation/process instruction.... */

catch ( const MediaAccess::LoadError& loadError ) {
// ^
// |
// +--- MQ/VSAM/POSIX STREAM/Whatever

// Report error (error info added to the error table,
// full instruction with parms/full proc.dump added
// to the diag.dump table)
context.setRetCode( HsaDataVector::rcInstructionError, //
oper.failed
loadError.getRetCodeReason(), // codes
loadError.getDetails() ); // text/descr.

/* .... next instruction .... */

As for out-of-memory:

http://groups.google.com/groups?as_umsgid=3CAF203B.44C9E6E8%40web.de
(see "such as/e.g. "bad_alloc" ...." bit)

regards,
alexander.

Andrei Alexandrescu

unread,
Apr 23, 2002, 9:23:27 AM4/23/02
to
"Igor Ivanov" <igiv...@yahoo.com> wrote in message
news:d117aff2.02042...@posting.google.com...

> try/ finally is unbeatable for its generality because the finally
> clause could contain any kind of code - several statements, macros -
> whatever. BTW they don't claim that their ScopeGuard solves all
> problems of resource protection. I am not sure I understand what you
> mean by "more flexibility".

I don't find 'finally' very general. For one thing, it can be simulated
in
C++ with a macro (at the cost of code duplication). Then, it separates
C++ the
place of "do"ing things from the place of "undo"ing them. Then, it
doesn't allow you to mention that you changed your mind about executing
the finally block (as it happens in transactional code). Finally (heee,
here's a pun [:o)]), you need to use a try-block, so the indentation
level of your code increases.


Andrei

Hillel Y. Sims

unread,
Apr 23, 2002, 10:40:09 AM4/23/02
to
What information will not be available at the throw point that is useful
to normal operation of the program (as opposed to just debugging use,
which I guess could be a useful application for this stuff, but just to
make that clear then)? If "one conceptual operation" fails, all
necessary context information should be available at the throw point
(file not found, invalid parameter, etc.) The intermediate call stack
context may be useful information for debugging, but I don't see how
normal operation would be based on that. Can you give an applied example
of this? I am probably not thinking widely enough..

try {
// perform a single conceptual "operation", it may fail somewhere
inside
db.open("blah blah");
}
catch (filenotfound_exc& exc) {
// here is some context of what happened to the operation,
// whatever it needs to tell me is given by virtue of exception type
and data
cout << "couldn't open " << exc.what() << endl;
}

Aside for debugging purposes, if the "operation" is encapsulated
properly, the catcher shouldn't need to know what exact control path was
taken internally to arrive at that point... ?

hys

"Nicola Musatti" <obje...@divalsim.it> wrote in message

news:3CC3D343...@divalsim.it...


> Still, you do know that the sequence of operations contained in the
> try block failed; in a well layered program this should refer to one
> conceptual operation within the current layer and you can provide the
> user with information about that. This information is usually neither
> available at the throw point nor at the user interface.
>

--


Hillel Y. Sims
hsims AT factset.com

Andrei Alexandrescu

unread,
Apr 23, 2002, 11:47:54 AM4/23/02
to
"Hillel Y. Sims" <use...@phatbasset.com> wrote in message
news:9n4x8.40134$7e5.12...@news02.optonline.net...

> What information will not be available at the throw point that is
useful
> to normal operation of the program (as opposed to just debugging
use,
> which I guess could be a useful application for this stuff, but just
to
> make that clear then)?

The dynamic execution point.

> If "one conceptual operation" fails, all
> necessary context information should be available at the throw point
> (file not found, invalid parameter, etc.) The intermediate call
stack
> context may be useful information for debugging, but I don't see how
> normal operation would be based on that. Can you give an applied
example
> of this? I am probably not thinking widely enough..

A very simple example is: you write a DB transaction that logs in,
executes a query, fetches a recordset, and returns some field in the
recordset.

At the very bottom layer, there's a function that makes sure the data
transferred satisfies type and size constraints. That function doesn't
have any idea on field name, user name etc. It throws an exception and
you get the following noninformative message:

"Data size mismatch"

It could be that you passed in too long a username or password during
login; or it could be that the query has a mistake; or it could be
that the database structure changed. You cannot know unless the
dynamic execution stack leaves traces in the message.

This actually happened in real world, and so often, that many took it
for granted, thinking that database programming is hard (!).

What you do want to see is:

"Data size mismatch while fetching field 'UserInfo' from query
'GetData'."


Andrei

Ionut Constantin

unread,
Apr 24, 2002, 9:07:54 AM4/24/02
to
Is there any transcript of Andrei's session on Error handling ? Any
planned follow-ups in CUJ Experts' site ?

Thanks,
Ionut

Nicola Musatti

unread,
Apr 24, 2002, 1:15:12 PM4/24/02
to

"Hillel Y. Sims" wrote:
>
> What information will not be available at the throw point that is useful
> to normal operation of the program (as opposed to just debugging use,
> which I guess could be a useful application for this stuff, but just to
> make that clear then)? If "one conceptual operation" fails, all
> necessary context information should be available at the throw point
> (file not found, invalid parameter, etc.) The intermediate call stack
> context may be useful information for debugging, but I don't see how
> normal operation would be based on that. Can you give an applied example
> of this? I am probably not thinking widely enough..

Consider a file transfer a distributed file system, such as NFS, that is
configurable to use both connection oriented and connectionless
transport protocols, such as TCP and UDP.

The original exception may well be thrown as "cable disconnected" by the
ethernet layer, however the way this error is interpreted at the
transport layer is indispensible for the correct working of the top
layer and is different for each type of transport.

Cheers,
Nicola Musatti

0 new messages