Topic: Exception Handling
Author: blargg@flash.net (Gargantua Blargg)
Date: 1998/11/20 Raw View
In article <3651992c.601297661@news.motu.com>, abrahams@spam.motu.com wrote:
> On 17 Nov 98 15:25:17 GMT, Christopher Eltschka
> <celtschk@physik.tu-muenchen.de> wrote:
>
> >However, maybe it would be helpful if uncaught_exception didn't
> >return a bool, but an int which tells you _how many_ uncaught
> >exceptions there are. Due to the automatic conversion int->bool,
> >code which would be broken by this would probably be rare.
I definitely like this idea. I could go implement it on the compiler I use
(they provude the exception runtime source), but I wouldn't have access to
it in any other compiler, so...
> That would certainly make uncaught_exception more useful. Probably
> that change should be made. Unfortunately, I don't think there's any
> way to make it useful for its purported intended purpose: deciding
> whether throwing from a destructor is safe.
It does allow things that were not possible when it just returned bool.
The transaction rollback example posted would now work even if it were
called during stack unwinding.
I think the change is totally logical and how it should have been defined
all along. It allows code to be logically nested properly.
--
blarggflash.net | Gargantua Blargg | http://www.flash.net/~blargg/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/11/18 Raw View
On 17 Nov 98 15:25:17 GMT, Christopher Eltschka
<celtschk@physik.tu-muenchen.de> wrote:
>However, maybe it would be helpful if uncaught_exception didn't
>return a bool, but an int which tells you _how many_ uncaught
>exceptions there are. Due to the automatic conversion int->bool,
>code which would be broken by this would probably be rare.
That would certainly make uncaught_exception more useful. Probably
that change should be made. Unfortunately, I don't think there's any
way to make it useful for its purported intended purpose: deciding
whether throwing from a destructor is safe.
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/11/17 Raw View
Valentin Bonnard wrote:
>
> Gargantua Blargg wrote:
>
> > First off, a phrase I've used so much, I'm replacing it with an acronym:
> >
> > **** DIDSUCE - Destructor Invoked During Stack Unwinding Caused by an Exception
>
> Nice !
>
> > Basically, Paul's saying uncaught_exception() is only useful on the
> > highest level of exception catching.
>
> Yes: while the exception mechanism allows any number of exceptions
> at the same time which don't interract, uncaught_exception() doesn't
> keep this property.
>
> What would you say if a function got its backtrace, then changed
> its behaviour depending on the name of its caller ?
>
> int strange ()
> {
> if (backtrace().immediate_caller() == "a()")
> return 1;
> else
> return 3;
> }
>
> void a()
> {
> cout << strange ();
> }
>
> void b()
> {
> cout << strange ();
> }
>
> Would you consider that acceptable ?
Seens strange.
However, maybe it would be helpful if uncaught_exception didn't
return a bool, but an int which tells you _how many_ uncaught
exceptions there are. Due to the automatic conversion int->bool,
code which would be broken by this would probably be rare.
With this changed uncaught_exception, the AtomicTransaction
could be implemented like this:
class AtomicTransaction
{
AtomicTransaction(): init_uncaught(uncaught_exception()) {}
~AtomicTransaction()
{
if (uncaught_exception() != init_uncaught)
{
// *additional* exceptions have been thrown
unroll();
}
else
{
// no additional exceptions have been thrown
commit();
}
}
void perform(int step);
private:
void* operator new(size_t); // will only work for automatic vars!
int init_uncaught; // contains the number of uncaught exceptions on
init
// ...
};
Now, we can do
void do_transaction()
{
AtomicTransaction trans;
trans.perform(1);
if (some_condition)
throw "failed";
trans.perform(2);
}
Now, if the code inside the function throws, the number of
unhandled exceptions will have increased by one (namely the one
thrown in do_transaction), and the transaction will be unrolled.
If, however, the code doesn't throw, the number of unhandled
exceptions will be the same as for construction, and therefore
the transaction will be committed.
Note that this would be independent of the number of active
exceptions when do_transaction was called. The number of
exceptions at that point is used as "false" value by
AtomicTransaction.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: AllanW@my-dejanews.com
Date: 1998/11/11 Raw View
> stephen.clamage@sun.com (Steve Clamage) wrote:
> >I don't dispute the desirabilty of reporting errors as early as possible.
> >I just haven't seen an example where throwing an exception from a
> >destructor was the only good solution. For example, the manager
> >can have a release function that reports whether the release
> >succeeded. The destructor calls the release function (which keeps
> >track of whether the resource was already released).
> >When you care about release success, you call release and note
> >the status. If you don't care whether the release succeeded, you
> >destroy the manager object normally.
> >It seems to me this is no less convenient to work with than
> >dealing with exceptions from destructors.
In article <01J3YURMPZGU0064MC@zebra.uas.se>,
abrahams@spam.motu.com wrote:
> Only a little. You need to remember to call the release function.
Read that paragraph again. You *don't* need to remember to call
the release function, if you don't need to know about failure.
The destructor takes care of it.
> >If you create a ManageResource as a variable or a member (as
> >opposed to a heap object), it is destroyed automatically at
> >scope exit. In that case, there isn't a really good place
> >to catch the exception.
>
> Of course, you'd also need to supply documentation saying that the
> object shouldn't be used as a member variable. Please note that I'm
> not advocating this as common practice, but which do you think is a
> more likely abuse: forgetting to call release() or using an object as
> a member when that's not allowed? I think the former.
Which is a good reason to make the explicit call optional. Fewer
opportunities for error usually means fewer errors.
--
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/11/12 Raw View
On 11 Nov 98 02:44:06 GMT, lisa_lippincott@advisories.com (Lisa
Lippincott) wrote:
>Steve Clamage wrote:
>> When you care about release success, you call release and note
>> the status. If you don't care whether the release succeeded, you
>> destroy the manager object normally.
>> It seems to me this is no less convenient to work with than
>> dealing with exceptions from destructors.
>
>David Abrahams replied:
>> Only a little. You need to remember to call the release function.
>
>That's a problem uncaught_exception can help with:
>
<destructor which asserts release has been called unless there's an
active exception snipped>
>In Steve Clamage's terms, the assertion forces you to care about
>release problems unless an exception is in the air. It's
>not a perfect solution, but it's the best I've found.
That solution finds usage errors at runtime, wheras mine always
produces correct code (at compile time). I know some people don't step
through every instruction, and more still don't check the branches of
their code that only get executed in case of an exception. Sometimes,
people like me who intend to check everything simply miss something. I
prefer the more foolproof approach.
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/11/12 Raw View
On 11 Nov 1998 16:54:50 GMT, blargg@flash.net (Gargantua Blargg)
wrote:
>Basically, Paul's saying uncaught_exception() is only useful on the
>highest level of exception catching. So, if we called the entire program
>from a DIDSUCE, there would be no other ill effects other than
>uncaught_exception() always returning true:
>
<snip>
>It's just that it is less than useful if a programmer does
>anything non-trivial in their destructors, even if that non-trivial stuff
>is wrapped in a try...catch construct.
After thinking about this some more, I think I see the point you're
trying to make. Let me summarize:
uncaught_exception() tells you whether an exception is unwinding.
Thus, throwing an exception when uncaught_exception() returns true
tells you either:
a. terminate() will be called, or
b. at least one exception will be leaked (not propagated).
using the result of uncaught_exception() to make a decision inside
code where an exception will be intentionally leaked doesn't tell you
anything.
The problem for the atomic transaction idiom occurs if someone tries
to use it in a destructor, where they're willing to proceed normally
even if the transaction fails:
X::~X() {
try { DoSomeAtomicTransaction(); }
catch(...) { /* leak an exception */ }
}
In real life, I expect this to be an extremely rare case. In the case
above, it is obviously acceptable to have the atomic transaction not
occur, but preferable that it does. Using uncaught_exception to
instigate rollback causes the transaction to act as though it failed,
and roll itself back (only if ~X is invoked due to another exception).
It is causing a difficulty because, as you say, the destructor is
trying to do something non-trivial which can throw an exception.
That's usually a bad idea anyway, of course.
If there were some alternative action (a way of accomplishing the same
thing as the try clause) in the catch clause this example would make
more sense. In that case, if ~X were invoked due to an exception, it
would be less efficient than it might otherwise have been: it would do
the entire atomic transaction, then unroll it and execute the catch
clause. Can anyone think of more serious consequences?
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/11/12 Raw View
On 11 Nov 1998 19:07:27 GMT, AllanW@my-dejanews.com wrote:
>In article <01J3YURMPZGU0064MC@zebra.uas.se>,
> abrahams@spam.motu.com wrote:
>> Only a little. You need to remember to call the release function.
>
>Read that paragraph again. You *don't* need to remember to call
>the release function, if you don't need to know about failure.
>The destructor takes care of it.
Okay, that works for me.
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/11/12 Raw View
Gargantua Blargg wrote:
> First off, a phrase I've used so much, I'm replacing it with an acronym:
>
> **** DIDSUCE - Destructor Invoked During Stack Unwinding Caused by an Exception
Nice !
> Basically, Paul's saying uncaught_exception() is only useful on the
> highest level of exception catching.
Yes: while the exception mechanism allows any number of exceptions
at the same time which don't interract, uncaught_exception() doesn't
keep this property.
What would you say if a function got its backtrace, then changed
its behaviour depending on the name of its caller ?
int strange ()
{
if (backtrace().immediate_caller() == "a()")
return 1;
else
return 3;
}
void a()
{
cout << strange ();
}
void b()
{
cout << strange ();
}
Would you consider that acceptable ?
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/11/10 Raw View
On 10 Nov 1998 06:55:36 GMT, "Paul D. DeRocco"
<pderocco@ix.netcom.com> wrote:
>
>abrahams@motu.com wrote:
>>
>> In article <36396107.816F5644@ix.netcom.com>,
>> "Paul D. DeRocco" <pderocco@ix.netcom.com> wrote:
>> > [code snipped]
<this was my AtomicTransaction code>
>> > Nice, but it still has the problem, true of all things that use
>> > uncaught_exception(), that it may be called while unwinding the
>> > stack on behalf of some unrelated exception that it doesn't have
>> > anything to do with, and be fooled into thinking it can't do
>> > something that it really can, or should do something that it
>> > mustn't, etc.
>>
>> With all due respect, it sounds like you are appealing to vague fears
>> here. Please justify your claim with an example.
>
>Consider a class that contains, say, a file handle that must be closed
>if it is open. Let's say that if there is an error closing the file, we
>want to report this with an exception, but we don't want to do this if
>it is illegal to throw an exception at that time. So we do this:
[code snipped]
I understand why your example has a problem, but that doesn't apply in
the case of my code which you said was "nice, but still has the
problem..." In fact, it doesn't look as though you read that code at
all. It is designed for the composition of atomic transactions (which
means if an exception occurs, the transaction is rolled back). Most
importantly, it isn't using uncaught_exception() to decide whether it
is allowed to throw an exception or not, but rather whether to roll
back. Your claim that all things using uncaught_exception() are
suspect is false.
-Dave
P.S. Computer programs can't be "fooled into thinking" anything unless
they interact with other buggy components. Programmers can be fooled
by inadequate, incorrect, or unclear documentation. The semantics of
uncaught_exception are clearly documented, and so shouldn't surprise
anyone.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/11/10 Raw View
stephen.clamage@sun.com (Steve Clamage) wrote:
>I don't dispute the desirabilty of reporting errors as early as possible.
>I just haven't seen an example where throwing an exception from a
>destructor was the only good solution. For example, the manager
>can have a release function that reports whether the release
>succeeded. The destructor calls the release function (which keeps
>track of whether the resource was already released).
>When you care about release success, you call release and note
>the status. If you don't care whether the release succeeded, you
>destroy the manager object normally.
>It seems to me this is no less convenient to work with than
>dealing with exceptions from destructors.
Only a little. You need to remember to call the release function.
>If you create a ManageResource as a variable or a member (as
>opposed to a heap object), it is destroyed automatically at
>scope exit. In that case, there isn't a really good place
>to catch the exception.
Of course, you'd also need to supply documentation saying that the
object shouldn't be used as a member variable. Please note that I'm
not advocating this as common practice, but which do you think is a
more likely abuse: forgetting to call release() or using an object as
a member when that's not allowed? I think the former.
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: lisa_lippincott@advisories.com (Lisa Lippincott)
Date: 1998/11/11 Raw View
Steve Clamage wrote:
> I don't dispute the desirabilty of reporting errors as early as possible.
> I just haven't seen an example where throwing an exception from a
> destructor was the only good solution. For example, the manager
> can have a release function that reports whether the release
> succeeded. The destructor calls the release function (which keeps
> track of whether the resource was already released).
> When you care about release success, you call release and note
> the status. If you don't care whether the release succeeded, you
> destroy the manager object normally.
> It seems to me this is no less convenient to work with than
> dealing with exceptions from destructors.
David Abrahams replied:
> Only a little. You need to remember to call the release function.
That's a problem uncaught_exception can help with:
Resource::~Resource()
{
if ( !this->Released() )
{
assert( std::uncaught_exception() );
try
{ this->Release(); }
catch (...)
{ /* logging or debugging */ }
}
}
In Steve Clamage's terms, the assertion forces you to care about
release problems unless an exception is in the air. It's
not a perfect solution, but it's the best I've found.
--Lisa Lippincott
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: blargg@flash.net (Gargantua Blargg)
Date: 1998/11/11 Raw View
In article <36487248.1428063@news.motu.com>, abrahams@spam.motu.com wrote:
> On 10 Nov 1998 06:55:36 GMT, "Paul D. DeRocco"
> <pderocco@ix.netcom.com> wrote:
>
> >abrahams@motu.com wrote:
> >>
> >> In article <36396107.816F5644@ix.netcom.com>,
> >> "Paul D. DeRocco" <pderocco@ix.netcom.com> wrote:
> >>
> >> > [code snipped]
>
> <this was my AtomicTransaction code>
Very nice and cool, I might add. I saved your code for later study of the
idea. It was very elegant.
> >> > Nice, but it still has the problem, true of all things that use
> >> > uncaught_exception(), that it may be called while unwinding the
> >> > stack on behalf of some unrelated exception that it doesn't have
> >> > anything to do with, and be fooled into thinking it can't do
> >> > something that it really can, or should do something that it
> >> > mustn't, etc.
First off, a phrase I've used so much, I'm replacing it with an acronym:
**** DIDSUCE - Destructor Invoked During Stack Unwinding Caused by an Exception
It refers to the body of the destructor of X below, in the particular
context it is called in.
Basically, Paul's saying uncaught_exception() is only useful on the
highest level of exception catching. So, if we called the entire program
from a DIDSUCE, there would be no other ill effects other than
uncaught_exception() always returning true:
before:
int main()
{
// program here
// ...
}
after:
struct X
{
~X()
{
// program here
// ...
}
};
int main()
{
try
{
X x;
throw 1234;
}
// X::~X() called here, which runs entire program
catch ( ... )
{
}
}
This breaks every use of uncaught_exception() inside the program, since it
always returns true.
...
[example involving use of logging function that uses uncaught_exception(),
called from a DIDSUCE - snipped]
...
> I understand why your example has a problem, but that doesn't apply in
> the case of my code which you said was "nice, but still has the
> problem..."
After my example above, I believe it applies to *all* code that uses
uncaught_exception(), and is called from a DIDSUCE.
> In fact, it doesn't look as though you read that code at
> all.
I would say the same thing about you reading his code :-) but I won't...
oops, too late. Just take Paul's example code and replace the
implementation of the logging function (called from the DIDSUCE) with an
implementation that uses your rollback mechanism.
> It is designed for the composition of atomic transactions (which
> means if an exception occurs, the transaction is rolled back). Most
> importantly, it isn't using uncaught_exception() to decide whether it
> is allowed to throw an exception or not, but rather whether to roll
> back.
But the important fact is that it *is* using uncaught_exception(), which
is rendered meaningless when called inside code from a DIDSUCE.
> Your claim that all things using uncaught_exception() are
> suspect is false.
suspect != bad code
In light of the issues I have articulated, I agree with Paul that code
using uncaught_exception() is suspect.
> P.S. Computer programs can't be "fooled into thinking" anything unless
> they interact with other buggy components. Programmers can be fooled
> by inadequate, incorrect, or unclear documentation. The semantics of
> uncaught_exception are clearly documented, and so shouldn't surprise
> anyone.
I agree. It's just that it is less than useful if a programmer does
anything non-trivial in their destructors, even if that non-trivial stuff
is wrapped in a try...catch construct.
--
blarggflash.net | Gargantua Blargg | http://www.flash.net/~blargg/
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@motu.com
Date: 1998/11/09 Raw View
In article <36396107.816F5644@ix.netcom.com>,
"Paul D. DeRocco" <pderocco@ix.netcom.com> wrote:
> [code snipped]
>
> Nice, but it still has the problem, true of all things that use
> uncaught_exception(), that it may be called while unwinding the stack on
> behalf of some unrelated exception that it doesn't have anything to do
> with, and be fooled into thinking it can't do something that it really
> can, or should do something that it mustn't, etc.
With all due respect, it sounds like you are appealing to vague fears here.
Please justify your claim with an example.
-Dave
-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Christopher M. Gurnee" <gurnec_at_mediaone_dot_net@127.0.0.1>
Date: 1998/11/09 Raw View
Francis Glassborow wrote in message ...
>In article <Kms02.53$%21.513060@brnws01.ne.mediaone.net>, Christopher M.
>Gurnee <gurnec_at_mediaone_dot_net@127.0.0.1> writes
>>Here's the reference you're looking for:
>>
>>15.3 Handling an exception
>>12 The scope and lifetime of the parameters of a function or
>>constructor extend into the handlers of a function-try-block.
>
>But they extend into, I think this is different from saying 'They are in
>the scope of'. I think the current wording means that the parameters
>already exist before entry and their lifetime continues until after
>exit.
I assume you mean that the parameters exist in the function body and
continue to exist (their lifetime, that is) in the catch block of the
function-try-block; their lifetime ends at the end of the last catch
block. In that case, I agree with what you say. Do you disagree or
think that the wording in the standard is unclear? I'm not sure what
you're clarifying in your post....
-Chris Gurnee
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/11/09 Raw View
In article <SXy12.49$xE.86407@brnws01.ne.mediaone.net>, Christopher M.
Gurnee <gurnec_at_mediaone_dot_net@127.0.0.1> writes
>I assume you mean that the parameters exist in the function body and
>continue to exist (their lifetime, that is) in the catch block of the
>function-try-block; their lifetime ends at the end of the last catch
>block. In that case, I agree with what you say. Do you disagree or
>think that the wording in the standard is unclear? I'm not sure what
>you're clarifying in your post....
I was not 'clarifying' I think the wording is ambiguous.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/11/10 Raw View
abrahams@motu.com wrote:
>
> In article <36396107.816F5644@ix.netcom.com>,
> "Paul D. DeRocco" <pderocco@ix.netcom.com> wrote:
> > [code snipped]
> >
> > Nice, but it still has the problem, true of all things that use
> > uncaught_exception(), that it may be called while unwinding the
> > stack on behalf of some unrelated exception that it doesn't have
> > anything to do with, and be fooled into thinking it can't do
> > something that it really can, or should do something that it
> > mustn't, etc.
>
> With all due respect, it sounds like you are appealing to vague fears
> here. Please justify your claim with an example.
Consider a class that contains, say, a file handle that must be closed
if it is open. Let's say that if there is an error closing the file, we
want to report this with an exception, but we don't want to do this if
it is illegal to throw an exception at that time. So we do this:
class file {
int handle; // file handle
bool is_open; // true if open
public:
class file_error {}; // an exception class
bool close(); // returns true if error
C1(const char* n); // defined elsewhere
~C1(); // defined below
write(const char* s); // defined elsewhere
};
C1::~C1() { // close file, report error if possible
if (is_open && close(handle) && !uncaught_exception())
throw file_error();
}
Now, let's say we write a function that uses this capability, and
catches and handles the exception:
void write_log(const string& s) {
try {
file f("logfile");
write(s);
}
catch (const file_error&) {
++num_log_errors; // a global variable
}
}
Next, we use this function inside the destructor for some other class:
class foobar {
public:
~foobar();
};
foobar::~foobar() {
write_log("deleting a foobar");
}
Now, let's construct one of these on the stack, throw an exception, and
see what happens:
void test() {
foobar f();
throw "Hi, mom!";
}
The foobar f is destroyed during the stack unwinding from the throw. Its
destructor calls write_log, which opens a file called "logfile" and
tries to write the message "deleting a foobar" to it. Let's say the
operation completes normally, due to buffering, but when file f is
destroyed and the file handle is really closed, it discovers the disk is
full. At this point, it wants to throw a file_error. Doing so is
perfectly safe, because it will be caught inside write_log, and so will
never "leak out" and supercede the stack unwinding that was happening as
a result of throwing "Hi, mom!". However, when it checks to see if it is
safe to throw an exception by calling uncaught_exception(), the latter
returns true because, yes, there is an uncaught exception at that point,
however irrelevent.
My first thought was that on entry to the inner try block, inside
write_log, uncaught_exception should begin returning false again.
However, it is only file_error that is safe to throw inside that try
block, not all other exceptions. There is no parameterless function that
can tell us whether or not the exception we'd like to throw will corrupt
the stack unwinding in progress on behalf of some other exception. That
can only be known by specifying what exception you'd like to throw, a la
"is_it_safe_to_throw_a(const type_info&)". A more elegant approach would
be a built-in throw_if_safe operator.
--
Ciao,
Paul
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/11/07 Raw View
In article <Kms02.53$%21.513060@brnws01.ne.mediaone.net>, Christopher M.
Gurnee <gurnec_at_mediaone_dot_net@127.0.0.1> writes
>Here's the reference you're looking for:
>
>15.3 Handling an exception
>12 The scope and lifetime of the parameters of a function or
>constructor extend into the handlers of a function-try-block.
But they extend into, I think this is different from saying 'They are in
the scope of'. I think the current wording means that the parameters
already exist before entry and their lifetime continues until after
exit.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Joe Keane <jgk@jgk.org>
Date: 1998/11/02 Raw View
In article <717lh8$jds$1@engnews1.eng.sun.com>
stephen.clamage@sun.com (Steve Clamage) writes:
>The uncaught_exception function was added at the request of
>people who really wanted to be able to throw exceptions
>from destructors. (Why? I don't know.)
Shit happens.
Destructors do non-trivial things, and non-trivial things can fail.
You can't just say `that shouldn't happen'. Of course whatever it is
shouldn't happen, that's why it's an error! The question is, what are
you going to do about it when it does happen? Or what is your scheme
to write programs so that it's truly impossible?
In article <3637a821.525820469@news.motu.com>
abrahams@spam.motu.com (David Abrahams) writes:
>It's one of those rare things for which there is sometimes a use, and
>when you need it there's no other way to do what you want. For
>example, imagine a class that manages a resource and releases it upon
>destruction (e.g. closes a file). If it is used as part of a process
>which is going to reacquire the resource later, reporting a failure to
>release the resource early could save lots of time. If the resource
>can't be properly released as part of exception-unwinding, however, it
>may not be so important to report the error.
More to the point, correct code does not lose errors. This is a
requirement in most projects. For example, if a `close' system call
fails, the program must handle it, not go on like everything is fine.
Of course, there may be special cases where it's known that a certain
error in a certain place is OK, but that's not what i'm talking about.
In article <36396107.816F5644@ix.netcom.com>
Paul D. DeRocco <pderocco@ix.netcom.com> writes:
>My position has always been that destroying an object (e.g., during
>stack unwinding) _means_ that you want it to go away without bothering
>you if something goes wrong. If you want to know about something going
>wrong, then invent an operation that explicitly closes the object.
I think that's generally right.
Unfortunately for you, C++ sets the policy and that's not it.
This is the `double error' problem which probably everyone has run
across. You hit an error, then in cleanup code, one of the cleanup
operations fails too. What to do now? Most coding guidelines say,
the cleanup code should do its best to clean things up, and the
function should report the original error.
Of course there can be some refinements, maybe production code does
that, while debug code dies right then so someone can look at it.
In some cases, this may be a logic error in the program. For example,
you try to free a pointer that's already free and that gives an error.
But in other cases, the program is fine, and it's something external.
The failed `close' system call above is probably like this.
Well there's no silver bullet. Error handling takes some thought.
C++ probably makes it easier to write code that does the right thing
most of the time.
--
Joe Keane, amateur mathematician
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/11/02 Raw View
Joe Keane <jgk@jgk.org> writes:
>In article <717lh8$jds$1@engnews1.eng.sun.com>
>stephen.clamage@sun.com (Steve Clamage) writes:
>>The uncaught_exception function was added at the request of
>>people who really wanted to be able to throw exceptions
>>from destructors. (Why? I don't know.)
>Destructors do non-trivial things, and non-trivial things can fail.
>You can't just say `that shouldn't happen'. Of course whatever it is
>shouldn't happen, that's why it's an error! The question is, what are
>you going to do about it when it does happen?
I don't disagree with what you say. I just don't agree that throwing
an exception from the destructor is the best way to deal with the
error, or even a good way. I suggested alternatives in another
article.
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Biju Thomas <bijuthom@ibm.net>
Date: 1998/11/05 Raw View
Christopher Eltschka wrote:
>
> What about the following code:
>
> struct X { ~X() { cout << "* I'm destructed" << endl; } };
>
> void f1(X x) try
> {
> throw "something";
> }
> catch(...)
> {
> cout << "* Exception caught" << endl;
> }
>
> void f2(X x)
> {
> try
> {
> throw "something";
> }
> catch(...)
> {
> cout << "Exception caught" << endl;
> }
> }
>
> IMHO f1 should print
>
> * I'm destructed
> * Exception caught
>
> while f2 should print
>
> * Exception caught
> * I'm destructed
IMHO, both should print:
* Exception caught
* I'm destructed
My reasoning goes like this: the X parameter is constructed before the
program enters the body of the function, and is destructed after the
body of the function is finished. In the first case, the body of the
function is a try-block, whereas, in the second case, the body of the
function is a block containing a try-block.
But I am not sure about this.
Can someone say whether this is correct or not, according to the
standard (if possible, with some pointer to the standard)?
Thanks,
Biju Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Nate Lewis" <nlewis@mindspring.com>
Date: 1998/11/06 Raw View
Biju Thomas wrote in message <3641FA50.F5C5FFB1@ibm.net>...
>>
>> What about the following code:
>>
>> struct X { ~X() { cout << "* I'm destructed" << endl; } };
>>
>> void f1(X x) try
>> {
>> throw "something";
>> }
>> catch(...)
>> {
>> cout << "* Exception caught" << endl;
>> }
>>
>> void f2(X x)
>> {
>> try
>> {
>> throw "something";
>> }
>> catch(...)
>> {
>> cout << "Exception caught" << endl;
>> }
>> }
>>
Christopher Eltschka wrote:
>IMHO, both should print:
>
> * Exception caught
> * I'm destructed
>
>My reasoning goes like this: the X parameter is constructed before the
>program enters the body of the function, and is destructed after the
>body of the function is finished. In the first case, the body of the
>function is a try-block, whereas, in the second case, the body of the
>function is a block containing a try-block.
>
>But I am not sure about this.
>
>Can someone say whether this is correct or not, according to the
>standard (if possible, with some pointer to the standard)?
This is correct. From the standard: "...The lifetime of a parameter
ends when the function in which it is defined returns. The
initialization and destruction of each parameter occurs within the
context of the calling function." [5.2.2/4]
--
Nate Lewis, MCSD
nlewis@mindspring.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Christopher M. Gurnee" <gurnec_at_mediaone_dot_net@127.0.0.1>
Date: 1998/11/06 Raw View
Biju Thomas wrote in message <3641FA50.F5C5FFB1@ibm.net>...
>
>IMHO, both should print:
>
> * Exception caught
> * I'm destructed
>
>My reasoning goes like this: the X parameter is constructed before the
>program enters the body of the function, and is destructed after the
>body of the function is finished. In the first case, the body of the
>function is a try-block, whereas, in the second case, the body of the
>function is a block containing a try-block.
>
>But I am not sure about this.
>
>Can someone say whether this is correct or not, according to the
>standard (if possible, with some pointer to the standard)?
<code to which Biju is refering is below>
Here's the reference you're looking for:
15.3 Handling an exception
12 The scope and lifetime of the parameters of a function or
constructor extend into the handlers of a function-try-block.
-Chris Gurnee
>Christopher Eltschka wrote:
> >
> > What about the following code:
> >
> > struct X { ~X() { cout << "* I'm destructed" << endl; } };
> >
> > void f1(X x) try
> > {
> > throw "something";
> > }
> > catch(...)
> > {
> > cout << "* Exception caught" << endl;
> > }
> >
> > void f2(X x)
> > {
> > try
> > {
> > throw "something";
> > }
> > catch(...)
> > {
> > cout << "Exception caught" << endl;
> > }
> > }
> >
> > IMHO f1 should print
> >
> > * I'm destructed
> > * Exception caught
> >
> > while f2 should print
> >
> > * Exception caught
> > * I'm destructed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/10/29 Raw View
Esa Pulkkinen <esap@cs.tut.fi> writes:
>> Can you similarly catch exceptions thrown by a base class destructor
>> in a derived class destructor using the function-try-block?
Francis Glassborow wrote:
> And just exactly how do you propose to do that? The derived class
> dtor has finished before the base class dtor executes.
So it can't be done. But this suggests a few questions based on
Esa's original question.
Q1. Can exceptions thrown by a derived class destructor be caught
in the base class destructor using a function-try block?
Q2. If the derived class inherits a virtual base class, is the
behavior any different?
Q3. What if the derived class inherits more than one base class?
Which base destructor catch-block gets invoked (or is this
a disallowed ambiguity)?
-- David R. Tribble, dtribble@technologist.com --
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/10/29 Raw View
In article <3638B801.2026@noSPAM.central.beasys.com>, David R Tribble
<david.tribble@noSPAM.central.beasys.com> writes
>Q1. Can exceptions thrown by a derived class destructor be caught
> in the base class destructor using a function-try block?
I think not, and a good reason is your subsequent questions
>
>Q2. If the derived class inherits a virtual base class, is the
> behavior any different?
I do not think that a virtual base can be destroyed until the objects
derived from it have been destroyed.
>Q3. What if the derived class inherits more than one base class?
> Which base destructor catch-block gets invoked (or is this
> a disallowed ambiguity)?
Well if it cannot catch at all then we have no problem.
The idea might seem attractive but I do not think we have a
comprehensive enough model of how destructors are required to work to
manage it. We know the semantics of destruction but not the
intermediate stages. If a destructor breaks down you are in trouble.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/10/30 Raw View
Steve Clamage wrote:
[...]
> The function-try-block was extended to all functions because
> there didn't seem to be any reason not to. There also isn't
> any use for it with non-constructors. For example, the following
> two function versions are entirely equivalent:
>
> #1
> int f() try
> {
> ... function body
> }
> catch (...)
> { ... }
>
> #2
> int f()
> {
> try {
> ... function body
> }
> catch(...)
> { ... }
> }
What about the following code:
struct X { ~X() { cout << "* I'm destructed" << endl; } };
void f1(X x) try
{
throw "something";
}
catch(...)
{
cout << "* Exception caught" << endl;
}
void f2(X x)
{
try
{
throw "something";
}
catch(...)
{
cout << "Exception caught" << endl;
}
}
IMHO f1 should print
* I'm destructed
* Exception caught
while f2 should print
* Exception caught
* I'm destructed
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/10/30 Raw View
abrahams@spam.motu.com (David Abrahams) writes:
>On 28 Oct 1998 18:31:11 GMT, stephen.clamage@sun.com (Steve Clamage)
>wrote:
>>My question is why it would be a good design to throw the
>>exception only sometimes, and if you can sometimes get along
>>without throwing it, why not always get along without
>>throwing it? Maybe that's what Paul meant by "not very useful".
>It's one of those rare things for which there is sometimes a use, and
>when you need it there's no other way to do what you want. For
>example, imagine a class that manages a resource and releases it upon
>destruction (e.g. closes a file). If it is used as part of a process
>which is going to reacquire the resource later, reporting a failure to
>release the resource early could save lots of time. If the resource
>can't be properly released as part of exception-unwinding, however, it
>may not be so important to report the error.
I don't dispute the desirabilty of reporting errors as early
as possible.
I just haven't seen an example where throwing an exception from a
destructor was the only good solution. For example, the manager
can have a release function that reports whether the release
succeeded. The destructor calls the release function (which keeps
track of whether the resource was already released).
When you care about release success, you call release and note
the status. If you don't care whether the release succeeded, you
destroy the manager object normally.
It seems to me this is no less convenient to work with than
dealing with exceptions from destructors. If you create a
ManageResource as a variable or a member (as opposed to a heap
object), it is destroyed automatically at scope exit. In that
case, there isn't a really good place to catch the exception.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/30 Raw View
David R Tribble wrote:
>
> Q1. Can exceptions thrown by a derived class destructor be caught
> in the base class destructor using a function-try block?
My position, contrary to Francis, is that the reverse is possible, but
this is impossible. Conceptually (and usually physically),
Derived::~Derived() calls Base::~Base(), and not the other way around.
The same is true of constructors: Derived::Derived() calls Base::Base().
> Q2. If the derived class inherits a virtual base class, is the
> behavior any different?
Nope.
> Q3. What if the derived class inherits more than one base class?
> Which base destructor catch-block gets invoked (or is this
> a disallowed ambiguity)?
As I said, the base catch block only catches exceptions thrown by
itself. There is no ambiguity.
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Bahman Safinejad <bahman.safinejad@ntc.nokia.com>
Date: 1998/10/30 Raw View
Esa Pulkkinen wrote:
> I have seen one case where a vendor used a destructor that threw an
> exception. Then the same vendor used it in a code like this: (It was
> used to convert old-style error codes to exceptions)
>
> Bar *f()
> {
> Foo foo; // the destructor of this object throws an exception.
> // ...
> Error *err = f1();
> foo.SetException(err);
> // ... some code that doesn't throw exceptions ...
> return new Bar;
> }
>
> Of course, this code is evil, and I've reported it as a bug.
>
> I've never seen any other examples of throwing an exception from a
> destructor. Given this experience, and the fact that there are a lot of
> other pitfalls throwing from a destructor, I would be ready to disallow
> throwing exceptions from destructors altogether.
You're right. Almost. In very rare cases you could need to let an exception be
thrown from an dtor.
One such case is when the dtor of a persistent object is invoked, by delete or
reaching end of scope, and when the object tries to flush its
cached data to the table they belong to. If something goes wrong, because of
connection time-out or no available transactions for example, an
exception would be raised by the underlying machinery. Ignoring the exception
in such a case is probably worse than throwing it, since it would
cause data being lost and inconsistent!
One way out of it is to force the users of the object to periodically call a
'flush' or 'saveDB' function.
However this work-around is not elegant, and exposes some lower level issues
that the persistent object was constructed to hide in the first
place!
--
Bahman Safinejad
mailto:bahman.safinejad@ntc.nokia.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/30 Raw View
Steve Clamage wrote:
>
> The uncaught_exception function was added at the request of
> people who really wanted to be able to throw exceptions
> from destructors. (Why? I don't know.)
>
> It isn't safe to throw an exception from a dtor unless you
> know that you aren't currently unwinding the stack due to
> another exception. The function allows you to find out
> whether throwing the exception is safe.
>
> My question is why it would be a good design to throw the
> exception only sometimes, and if you can sometimes get along
> without throwing it, why not always get along without
> throwing it? Maybe that's what Paul meant by "not very useful".
I agree with you entirely. However, the reason I said
uncaught_exception() isn't very useful is that, as someone else pointed
out a while back, it may return true even when it _is_ safe to throw an
exception. During the process of unwinding the stack, it is perfectly
legal to execute code that uses exceptions completely internally, as
long as those exceptions don't "leak out" and conflict with the original
exception. However, uncaught_exception() can't detect this situation, so
returns true. I suggested it might start returning false again on entry
to another try block, but it was pointed out that this only works if all
possible exceptions are caught by that try block. If only some are, and
some are allowed to propagate, a call to uncaught_exception() inside the
try block can't assume it's safe to throw an exception, even if the
programmer knows that what he wants to throw will be caught before
leaking into some destructor's code. The only solution would be a
function like "can_i_safely_throw_a(const type_info&)", or a new
built-in keyword like "throw_if_safe" that does nothing but evaluate its
argument if throwing it would invoke terminate().
> The function-try-block is useful only for constructors. If the
> constructor for a member or base of a class C exits via an
> exception, there was previously no way for the C constructor to
> find out about it or intercept the exception. The function-try-
> block can catch any exception thrown by the constructor of a
> base or member.
>
> The function-try-block was extended to all functions because
> there didn't seem to be any reason not to. There also isn't
> any use for it with non-constructors.
I'm not sure what use they have even with constructors. A function try
block isn't allowed to "handle" the exception fully, in that the
exception is still propagated afterwards, even if there is no "throw"
inside the catch clause. This makes sense, because the object isn't
valid at that point. But it also means that there is code inside the
definition of Derived::Derived() that can't even assume that the Base
part of the object is valid. This seems like a dangerous thing to allow.
I can't imagine why I'd want to intercept an exception in a derived
class that was thrown before the base class part of the object was fully
constructed. Is there some real-world idiom where this is actually
useful?
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/30 Raw View
David Abrahams wrote:
>
> It's one of those rare things for which there is sometimes a use, and
> when you need it there's no other way to do what you want. For
> example, imagine a class that manages a resource and releases it upon
> destruction (e.g. closes a file). If it is used as part of a process
> which is going to reacquire the resource later, reporting a failure to
> release the resource early could save lots of time. If the resource
> can't be properly released as part of exception-unwinding, however, it
> may not be so important to report the error.
My position has always been that destroying an object (e.g., during
stack unwinding) _means_ that you want it to go away without bothering
you if something goes wrong. If you want to know about something going
wrong, then invent an operation that explicitly closes the object.
> That aside, uncaught_exception is extremely useful, even if you're not
> going to throw exceptions from your destructor. For example, the
> following technique allows the composition of atomic transactions:
[code snipped]
Nice, but it still has the problem, true of all things that use
uncaught_exception(), that it may be called while unwinding the stack on
behalf of some unrelated exception that it doesn't have anything to do
with, and be fooled into thinking it can't do something that it really
can, or should do something that it mustn't, etc.
> And the only reason you'd want to use it in a constructor is to
> translate an exception caused by a member or base class constructors
> into some other exception, in short, if your constructor isn't
> exception-neutral. I don't know why anyone would want to do that,
> except to avoid termination due to an exception-specification
> mismatch. Of course, I don't know why anyone would use an
> exception-specification other than throw(...) or throw() in the first
> place!
I agree, but it's an interesting potential use. I hadn't though of that
one.
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/11/02 Raw View
In article <36395D8C.6D8A06C6@ix.netcom.com>, Paul D. DeRocco
<pderocco@ix.netcom.com> writes
>My position, contrary to Francis, is that the reverse is possible, but
>this is impossible. Conceptually (and usually physically),
>Derived::~Derived() calls Base::~Base(), and not the other way around.
>The same is true of constructors: Derived::Derived() calls Base::Base().
The problem is that this does not actually work (conceptually) because
the object has ceased being a derived before the base destructor is
called. I do not think that the model of destruction/construction works
well with the cocepts of function calling.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1998/11/02 Raw View
Steve Clamage <stephen.clamage@sun.com> wrote:
: The function-try-block was extended to all functions because
: there didn't seem to be any reason not to. There also isn't
: any use for it with non-constructors. For example, the following
: two function versions are entirely equivalent:
: #1
: int f() try
: {
: ... function body
: }
: catch (...)
: { ... }
: #2
: int f()
: {
: try {
: ... function body
: }
: catch(...)
: { ... }
: }
The two have identical finctionality, yes. But they are not
_entirely_ equivalent. For example, in (#1) it is impossible to
_accidently_ put things in the function body, but outside of
the try block.
Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1998/11/02 Raw View
David Abrahams <abrahams@spam.motu.com> wrote:
: I don't know why anyone would use an
: exception-specification other than throw(...) or throw() in the first
: place!
One such example is Corba. Corba provides a mechanism to call
methods on remote objects. If the method throws, the exception
will be propagated to the caller. The problem is that Corba only
knows how to propagate some particular exceptions, not an
arbitrary exception. It is your responsibility to ensure that
you don't throw anything that Corba doesn't know how to propagate.
Therefore it is actually advantegeous to put exception specs on the
methods called through a Corba mechanism, because if you allow wrong
thing to escape, you will only make things worse. Corba also happens
to enforce this practice, because if you don't put exception specs,
your method will not override whatever it must override.
Fortunately enough, there is a way to deal with this mess cetrally.
Namely, you install your own unexpected(), which converts everything
into a CORBA::SystemException. Not having any exception specs
anywhere else helps, because you can execute set_unexpected() only
once and not set/restore unexpected() --in every Corba method.
Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/28 Raw View
Eric Lemings wrote:
>
> Can anyone summarize the difference, if any, between
> exception handling as specified in the ARM and exception
> handling as specified in the standard?
They added the uncaught_exception() function, which tells (not very
usefully) whether or not there is an exception in the process of being
thrown. They added function-try-blocks, which I've yet to find a use
for. Those are the only differences I can think of off-hand.
--
Ciao,
Paul
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/10/28 Raw View
"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
>> Can anyone summarize the difference, if any, between
>> exception handling as specified in the ARM and exception
>> handling as specified in the standard?
>They added the uncaught_exception() function, which tells (not very
>usefully) whether or not there is an exception in the process of being
>thrown. They added function-try-blocks, which I've yet to find a use
>for. Those are the only differences I can think of off-hand.
The uncaught_exception function was added at the request of
people who really wanted to be able to throw exceptions
from destructors. (Why? I don't know.)
It isn't safe to throw an exception from a dtor unless you
know that you aren't currently unwinding the stack due to
another exception. The function allows you to find out
whether throwing the exception is safe.
My question is why it would be a good design to throw the
exception only sometimes, and if you can sometimes get along
without throwing it, why not always get along without
throwing it? Maybe that's what Paul meant by "not very useful".
The function-try-block is useful only for constructors. If the
constructor for a member or base of a class C exits via an
exception, there was previously no way for the C constructor to
find out about it or intercept the exception. The function-try-
block can catch any exception thrown by the constructor of a
base or member.
The function-try-block was extended to all functions because
there didn't seem to be any reason not to. There also isn't
any use for it with non-constructors. For example, the following
two function versions are entirely equivalent:
#1
int f() try
{
... function body
}
catch (...)
{ ... }
#2
int f()
{
try {
... function body
}
catch(...)
{ ... }
}
--
Steve Clamage, stephen.clamage@sun.com
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Esa Pulkkinen <esap@cs.tut.fi>
Date: 1998/10/28 Raw View
stephen.clamage@sun.com (Steve Clamage) writes:
> The uncaught_exception function was added at the request of
> people who really wanted to be able to throw exceptions
> from destructors. (Why? I don't know.)
I have seen one case where a vendor used a destructor that threw an
exception. Then the same vendor used it in a code like this: (It was
used to convert old-style error codes to exceptions)
Bar *f()
{
Foo foo; // the destructor of this object throws an exception.
// ...
Error *err = f1();
foo.SetException(err);
// ... some code that doesn't throw exceptions ...
return new Bar;
}
Of course, this code is evil, and I've reported it as a bug.
I've never seen any other examples of throwing an exception from a
destructor. Given this experience, and the fact that there are a lot of
other pitfalls throwing from a destructor, I would be ready to disallow
throwing exceptions from destructors altogether.
>The function-try-block is useful only for constructors. If the
[SNIP]
> or intercept the exception. The function-try- block can catch any
> exception thrown by the constructor of a base or member.
Can you similarly catch exceptions thrown by a base class destructor in
a derived class destructor using the function-try-block? I can't find
anything saying that in the CD2, but perhaps I've missed something? It
could be used to "fix" those defective classes whose destructor (perhaps
accidentally?) threw an exception, but which you can't change. At least
in egcs-1.1, using function-try-block in a destructor didn't catch the
exception thrown by the base class destructor. Assuming the compiler is
correct, why was it defined like that?
--
Esa Pulkkinen | C++ programmers do it virtually
E-Mail: esap@cs.tut.fi | everywhere with class, resulting
WWW : http://www.cs.tut.fi/~esap/ | in multiple inheritance.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/10/29 Raw View
Steve Clamage <stephen.clamage@sun.com> writes:
> For example, the following
> two function versions are entirely equivalent:
Please let me repeat what you are saying:
For example, the following two function versions
are entirely equivalent:
#1
int f(SomeUserDefinedType) try
{
... function body
}
catch (...)
{ ... }
#2
int f(SomeUserDefinedType)
{
try {
... function body
}
catch(...)
{ ... }
}
(SomeUserDefinedType might throw in the structors)
--
Valentin Bonnard mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/10/29 Raw View
In article <wbur9vsl9qx.fsf@kaarne.cs.tut.fi>, Esa Pulkkinen
<esap@cs.tut.fi> writes
>Can you similarly catch exceptions thrown by a base class destructor in
>a derived class destructor using the function-try-block?
And just exactly how do you propose to do that? The derived class dtor
has finished before the base class dtor executes.
Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: abrahams@spam.motu.com (David Abrahams)
Date: 1998/10/29 Raw View
On 28 Oct 1998 18:31:11 GMT, stephen.clamage@sun.com (Steve Clamage)
wrote:
>
>"Paul D. DeRocco" <pderocco@ix.netcom.com> writes:
>
>>They added the uncaught_exception() function, which tells (not very
>>usefully) whether or not there is an exception in the process of being
>>thrown. They added function-try-blocks, which I've yet to find a use
>>for. Those are the only differences I can think of off-hand.
<good explanation of why uncaught_exception() was added and throwing
from destructors snipped>
>My question is why it would be a good design to throw the
>exception only sometimes, and if you can sometimes get along
>without throwing it, why not always get along without
>throwing it? Maybe that's what Paul meant by "not very useful".
It's one of those rare things for which there is sometimes a use, and
when you need it there's no other way to do what you want. For
example, imagine a class that manages a resource and releases it upon
destruction (e.g. closes a file). If it is used as part of a process
which is going to reacquire the resource later, reporting a failure to
release the resource early could save lots of time. If the resource
can't be properly released as part of exception-unwinding, however, it
may not be so important to report the error.
That aside, uncaught_exception is extremely useful, even if you're not
going to throw exceptions from your destructor. For example, the
following technique allows the composition of atomic transactions:
// Some details omitted here for clarity
class Action
{
public:
virtual void Do() = 0;
virtual void Undo() throw() = 0;
};
typedef std::auto_ptr<Action> OwnedAction;
class TransactionStep
{
public:
TransactionStep( OwnedAction act )
: action( act ) { action->Do(); }
~TransactionStep() {
if ( std::uncaught_exception() ) action->Undo(); }
private:
OwnedAction action;
};
void SomeAtomicTransaction( <...> )
{
TransactionStep step1(
OwnedAction( new Action1( <...> ) ) );
TransactionStep step2(
OwnedAction( new Action2( <...> ) ) );
TransactionStep step3(
OwnedAction( new Action1( <...> ) ) );
TransactionStep step4(
OwnedAction( new Action3( <...> ) ) );
};
>The function-try-block is useful only for constructors. If the
>constructor for a member or base of a class C exits via an
>exception, there was previously no way for the C constructor to
>find out about it or intercept the exception. The function-try-
>block can catch any exception thrown by the constructor of a
>base or member.
And the only reason you'd want to use it in a constructor is to
translate an exception caused by a member or base class constructors
into some other exception, in short, if your constructor isn't
exception-neutral. I don't know why anyone would want to do that,
except to avoid termination due to an exception-specification
mismatch. Of course, I don't know why anyone would use an
exception-specification other than throw(...) or throw() in the first
place!
By the way, a function-try-block is no help for a specification of
throw(), because you can't just eat the exception - it gets
automatically rethrown at the end of any catch block. The reasons for
this are obvious, if you think about it: construction of a base or
member failed. How would you recover and produce your
fully-constructed object?
>The function-try-block was extended to all functions because
>there didn't seem to be any reason not to. There also isn't
>any use for it with non-constructors. For example, the following
>two function versions are entirely equivalent:
I think whether it is even useful for constructors is up for debate...
;)
-Dave
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/10/27 Raw View
In article 7A0C7729@lmco.com, Eric Lemings <eric.b.lemings@lmco.com> writes:
>
>Can anyone summarize the difference, if any, between
>exception handling as specified in the ARM and exception
>handling as specified in the standard?
Exception handling is not specified very precisely in the ARM.
(It is marked as "experimental", after all.)
The standard goes into great detail, covering cases left unspecified
by the ARM. The essence is the same as in the ARM, however.
You get an electronic copy of the standard for $18 and read about
it yourself in chapter 15.
---
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Eric Lemings <eric.b.lemings@lmco.com>
Date: 1998/10/23 Raw View
Dear readers:
Can anyone summarize the difference, if any, between
exception handling as specified in the ARM and exception
handling as specified in the standard?
Thanks,
Eric.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: objsoft@netcom.com (ObjectSoftware)
Date: 1995/07/11 Raw View
Greetings:
I have a question on exception specification. The draft
contains exception specification in Section 15.4.
The question is:
How should a method be declared & defined if the method
possesses a "const" qualifier and an "exception-spec"
qualifier? i.e., which of the following is a valid
declaration & definition.
Scenario 1:
class X {
public:
void Something(void) const throw(int);
};
void X::Something(void) const throw(int)
{
//* something
}
Scenario 2:
class X {
public:
void Something(void) throw(int) const;
};
void X::Something(void) throw(int) const
{
//* something
}
I could not find a suitable answer to the Scenarios. Though, the
first one(Scenario 1) makes more sense.
Further questions:
a. Can a method with a "const" qualifier should be allowed to
throw an "exception". If yes, then the catch should be
evaluated so that the "const"ness of the method is maintained?
Any input on this is appreciated.
Thanks.
Bobby Sardana.
ObjectSoftware, Inc.
objsoft@netcom.com
C++ Development, Documentation & Testing Tools.
URL: ftp://ftp.netcom.com/pub/ob/objsoft/htmlinfo/Testing.html
Author: fenster@ground.cs.columbia.edu (Sam Fenster)
Date: 09 Mar 1995 21:27:12 GMT Raw View
jason@cygnus.com (Jason Merrill) writes:
> Michael Abbott <Michael@rcp.co.uk> writes:
> > What is defined to happen when an exception is thrown during exception
> > unwinding?
>
> 15.5.1 The terminate() function [except.terminate]
> ...
> --when a exception handling mechanism, after completing evaluation of
> the object to be thrown, calls a user function that exits via an
> uncaught exception)
> ...
> --when a destructor called during stack unwinding caused by an excep-
> tion tries to exit using an exception.
Wouldn't it be better (and possible) to allow the old (or new) exception to
continue propagating in these cases? It would be unfortunate if one could not
prevent a program from terminating because of exceptions in totally unrelated
parts.
Also, as someone else asked, if code inside a destructor throws AND CATCHES an
exception during unwinding of another exception, does that affect the
propagation of the original one? I sure hope not.
How does it work in other languages?
Author: Michael@rcp.co.uk (Michael Abbott)
Date: Tue, 07 Mar 1995 07:40:21 +0000 Raw View
In article <3j22s1$rcc@jalisco.optimum.net>,
tim_boemker@zacatecas.optimum.com (Tim Boemker) wrote:
> Is there any standard way to determine whether an exception is
> currently being handled?
>
> I have a situation in which a destructor checks for a state which is an
> error under normal circumstances (hence, it should throw an exception)
> but is not an error if an exception is already being handled. (To be
> specific, I am implementing a query class to access a database. Under
> normal circumstances, I'd like to throw an error if the query is
> destroyed before all the data have been returned, but when an exception
> is being handled I'd like to suppress the check.)
>
> Tim Boemker
> Optimum Group
I'd like to second this question and put it another way around:
What is defined to happen when an exception is thrown during exception
unwinding?
Author: Michael@rcp.co.uk (Michael Abbott)
Date: Wed, 08 Mar 1995 08:26:58 +0000 Raw View
In article <JASON.95Mar7094947@phydeaux.cygnus.com>,
jason@cygnus.com (Jason Merrill) wrote:
> >>>>> Michael Abbott <Michael@rcp.co.uk> writes:
>
> > What is defined to happen when an exception is thrown during exception
> > unwinding?
>
> 15.5.1 The terminate() function [except.terminate]
>
> 1 Occasionally, exception handling must be abandoned for less subtle
> error handling techniques. For example,
...
> --when a destructor called during stack unwinding caused by an excep-
> tion tries to exit using an exception.
...
>
> 2 In such cases,
> void terminate();
> is called; terminate() calls the function given on the most recent
> call of set_terminate()(_lib.exception.terminate_).
Ah. This makes the case for being able to detect exception handling in
progress rather acute, does it not?
I can see why this is done, after all doing anything else is rather hard.
On the other hand, in principle a destructor can call anything, so I'd expect
this situation might happen often.
Can the destructor set up its own try{}catch(){} block? Presumably so, so
I imagine that one can have arbitrary nests of unwinding exceptions, just so
long as they don't overlap.
What's your source? My copy of the ARM has something very similar in sections
15.6.1c and 15.6.2c.
Author: jason@cygnus.com (Jason Merrill)
Date: 07 Mar 1995 17:49:47 GMT Raw View
>>>>> Michael Abbott <Michael@rcp.co.uk> writes:
> What is defined to happen when an exception is thrown during exception
> unwinding?
15.5.1 The terminate() function [except.terminate]
1 Occasionally, exception handling must be abandoned for less subtle
error handling techniques. For example,
--when a exception handling mechanism, after completing evaluation of
the object to be thrown, calls a user function that exits via an
uncaught exception,77)
--when the exception handling mechanism cannot find a handler for a
thrown exception (see _except.handle_),
--when the exception handling mechanism finds the stack corrupted, or
--when a destructor called during stack unwinding caused by an excep-
tion tries to exit using an exception.
_________________________
77) For example, if the object being thrown is of a class with a copy
constructor, terminate() will be called if that copy constructor exits
with an exception during a throw.
2 In such cases,
void terminate();
is called; terminate() calls the function given on the most recent
call of set_terminate()(_lib.exception.terminate_).
Author: tim_boemker@zacatecas.optimum.com (Tim Boemker)
Date: 1 Mar 1995 15:12:01 GMT Raw View
Is there any standard way to determine whether an exception is
currently being handled?
I have a situation in which a destructor checks for a state which is an
error under normal circumstances (hence, it should throw an exception)
but is not an error if an exception is already being handled. (To be
specific, I am implementing a query class to access a database. Under
normal circumstances, I'd like to throw an error if the query is
destroyed before all the data have been returned, but when an exception
is being handled I'd like to suppress the check.)
Tim Boemker
Optimum Group
Author: jert@ceci.mit.edu (John Tedrow)
Date: 6 Nov 1993 18:38:32 GMT Raw View
Hi, I am currently looking into writing an exception handling mechanism
for C++. I am looking to find a way of getting most of the functionality
of excpetion handling by a software (not compiler, tho') solution by using
the setjump and longjump functions. I would appreciate any help in finding
either sources (ie journal articles, etc.) or code that would assist me
in this endeavor.
Thanks,
john
jert@MIT.EDU
Author: ahumphr@micrognosis.co.uk (Aidan Humphreys)
Date: 17 Dec 92 13:53:00 GMT Raw View
Can anyone provide some pointers to information re: exeption handling in
C++. My specific interest is real time software portable between UNIX and
VMS platforms. Which currently available compilers support it? How
does one integrate application exceptions with system signals? Are
current implementations trustworthy and stable?