Topic: Exceptions in destructors
Author: Nick Godbey <ngodbey@es.atl.sita.int>
Date: 1997/06/27 Raw View
Are there any pervailing conventions for throughing execptions
from destructors? Example
class Foo
{
public:
Foo() {}
~Foo() { ...; throw Error1; }
dosomething() { ...; throw Error2;}
};
main()
{
try
{
Foo bar;
bar.dosomething(); // this throughs an exceptions Error1.
}
catch( Error1 err)
{
}
catch ( Error2 err )
{
}
In this example the Error2 exception will never get handled
because the Error1 exception gets thrown latter(from the destructor).
An I understanding this correctly do we have another C++ faux pas.
thanx Nick Godbey
---
[ 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 ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/06/27 Raw View
Nick Godbey <ngodbey@es.atl.sita.int> writes:
> Are there any pervailing conventions for throughing execptions
> from destructors? Example
>
> class Foo
> {
> public:
> Foo() {}
> ~Foo() { ...; throw Error1; }
> dosomething() { ...; throw Error2;}
> };
> An I understanding this correctly do we have another C++ faux pas.
There was a long thread in c.l.c.m some time ago about exceptions
from dtors; actually, there are 4 topics:
1) what the std about exception thrown from dtor which provoke a stack
walkback
2) what the std about exception thrown from dtor because of a stack
walkback
3) what should say
4) it is a good idea to throw exception in dtor (during stack
walkback or not, and given possible changes in the std)
You example refer to 2), and the answer is to call terminate().
1) isn't very well defined in the std, but it seem very clear to
me what should be done (the process should be similar with ctor
and dtor, as completly constructed objects are destroyed in
reverse order, and object in an array are destroyed if they
aren't yet - the array case it especialy non handled by the
std). The operator delete which should be called normally is
called.
To call terminate () is IMO a hack and my answer to 3) is to
call a special double_fault function which can call terminate ()
or rethrow.
Given the current state of compilers, I am not sure that 4) is
a good idea now for portable code; even with more stable
compilers, I don't think that it's a good idea because of the
imprecise wording in the std.
With a more meaningfull wording, I think that it should at
least be safe to throw exceptions in dtors when they aren't
called because of a stack walkback.
T::~T ()
{
try {
do_stuff ();
}
catch (logable& excp)
{
if (! uncaugth_exception ())
throw;
else
error_log << excp;
}
catch (...)
{
if (! uncaugth_exception ())
throw;
}
}
--
Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std-c++@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++-request@ncar.ucar.edu
]
Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1995/12/05 Raw View
> ==========J. Kanze, 12/1/95==========
> Of course, with regards to exception safety, resource leaks are the
> least of your problems. What happens if the exception causes you to
> leave the internal data in some inconsistent state, which results in an
> endless loop (because of a cycle in a graph, for example) the next time
> you access the data structure.
Help in avoiding resource leaks in the face of exceptional
conditions that are best served by major unfolding of the
stack back to some handling point is what exception are
about. As such, they are potentially an advance over
setjump/longjump. Error handling always has "distorted"
code and that is why so many programmers have ignored it.
Of course you have to design and code your algotithms
so that exception can happen only at "safe" (in terms of
data consistency) points or are caught locally enough to
repair that before letting the exception go through.
Exceptions still have the potential for handling these
error cases in the least distorting way possible.
But the key word is "possible".
I think people want handling errors to be easier
and less "distorting" than is feasible.
What you get is a mechanism that does not handle
real problems very well because it is too naively simple.
Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: James Kanze US/ESC 60/3/141 #40763 <kanze@lts.sel.alcatel.de>
Date: 1995/12/07 Raw View
In article <DJ35vK.39x@falcon.daytonoh.attgis.com> Dick Menninger
<Dick.Menninger@daytonoh.attgis.com> writes:
|> > ==========J. Kanze, 12/1/95==========
|> > Of course, with regards to exception safety, resource leaks are the
|> > least of your problems. What happens if the exception causes you to
|> > leave the internal data in some inconsistent state, which results in an
|> > endless loop (because of a cycle in a graph, for example) the next time
|> > you access the data structure.
|> Help in avoiding resource leaks in the face of exceptional
|> conditions that are best served by major unfolding of the
|> stack back to some handling point is what exception are
|> about. As such, they are potentially an advance over
|> setjump/longjump. Error handling always has "distorted"
|> code and that is why so many programmers have ignored it.
|> Of course you have to design and code your algotithms
|> so that exception can happen only at "safe" (in terms of
|> data consistency) points or are caught locally enough to
|> repair that before letting the exception go through.
|> Exceptions still have the potential for handling these
|> error cases in the least distorting way possible.
|> But the key word is "possible".
|> I think people want handling errors to be easier
|> and less "distorting" than is feasible.
|> What you get is a mechanism that does not handle
|> real problems very well because it is too naively simple.
I think we basically agree. Exceptions do not solve any design
problems in error handling strategy; they are an implementation tool,
which may possibly simplify the implementation of the strategy once
the strategy has been decided upon. In the past, I have seen far to
many people pretending that with exceptions, all problems with error
handling and error reporting will disappear.
I think it must also be made clear that the "reduced distortion" comes
at a price. Exceptions have certain dangers (much the same ones as
goto). Much has been said about resource leaks, and how to handle
them. My only point in the above is that this is not the only danger
you must pay attention to. Typically, you program invariants are
invalid in significant blocks of code, since changes from on invariant
consistent state to another are not atomic. (As a typical example,
class invariants will often not hold at certain points in member
functions of the class.) Exception safety must also ensure that all
invariants *do* hold if the exception percolates up to a level at
which it is expected that they hold.
With regards to your comments, I do wonder if the fact that error
handling distorts your code is in some way a sign that your design did
not consider error recovery as a first class problem, at the same
level as all other possible behaviors. (I also wonder if maybe
exceptions aren't "too naively simple", as you put it.)
--
James Kanze Tel.: (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils, tudes et r alisations en logiciel orient objet --
-- A la recherche d'une activit dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/11/26 Raw View
kanze@gabi-soft.fr (J. Kanze) writes:
>Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
>|> schuenem@informatik.tu-muenchen.de (Ulf Schuenemann) writes:
>
>|> >How about saying that dtors have an empty exception-specification
>|> >(either by default or always) ?
>
>|> How does that help?
>
>|> >Then there are 3 cases possible:
>|> >- The dtor causes no eception.
>|> >- The dtor catches all exceptions and continues - save,
>|> > but what happens to client-provided exception handling ?
>|> >- The dtor does not handle an exception that happend to be
>|> > be raised - unexpected() is called.
>
>|> Yes, and what if the programmer has defined unexpected()
>|> to rethrow the exception? (In most circumstances, doing so
>|> is probably a much better idea than just crashing via
>|> a call to abort().)
>
>1. How can it know what the exception was to rethrow it? Is a throw
>without an argument legal here? (I don't think so, but I'm not sure.)
Yes, a `throw;' statement is legal within an unexpected() handler.
15.1/5-6 is quite clear:
| 5 A throw-expression with no operand rethrows the exception being han-
| dled without copying it.
|
| 6 The exception thrown is the one most recently caught and not finished.
| An exception is considered caught when initialization is complete for
| the formal parameter of the corresponding catch clause, or when termi-
| nate() or unexpected() is entered due to a throw. An exception is
| considered finished when the corresponding catch clause exits.
On entering unexpected(), the exception is considered handled, but not
finished, so `throw;' is fine.
The ARM contains an example of the use of `throw;' in an unexpected
handler (pages 365-366).
>2. This behavior doesn't seem conform to the required behavior in
>18.6.1.2. I believe that when a user provided routine violates required
>behavior, undefined behavior results.
Hmm, you're right - according to 18.6.1.2, an unexpected handler
must not throw the same exception. This would seem to imply that
`throw;' would be ok in an unexpected handler only if the exception didn't
escape, e.g.
void my_unexpected_handler() { try { throw; } catch(...) {} }
and also that the example in the ARM has undefined behaviour.
On the other hand, 15.5.2 definitely seems to assume that an
unexpected handler can throw an exception not in the exception
specification, and carefully describes the behaviour in that case.
So the draft is self-contradictory here. I think all you can really
say is that one of 15.5.2 and 18.6.1.2 is wrong.
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
I will have little or no net access from Nov 30 until Dec 25.
Please email me a copy of any follow-ups.
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/11/27 Raw View
Herb Sutter (herbs@interlog.com) wrote:
|> In article <494oog$hmf@gabi.gabi-soft.fr>,
|> kanze@gabi-soft.fr (J. Kanze) wrote:
|> >Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
|> >|> schuenem@informatik.tu-muenchen.de (Ulf Schuenemann) writes:
|> >|> >How about saying that dtors have an empty exception-specification
|> >|> >(either by default or always) ?
|> >
|> >|> How does that help?
|> I think he wants unexpected() to be called, rather than an inelegant
|> terminate(), when a dtor throws during unwinding.
|> >|> >Then there are 3 cases possible:
|> >|> >- The dtor causes no eception.
|> >|> >- The dtor catches all exceptions and continues - save,
|> >|> > but what happens to client-provided exception handling ?
|> >|> >- The dtor does not handle an exception that happend to be
|> >|> > be raised - unexpected() is called.
|> >
|> >|> Yes, and what if the programmer has defined unexpected()
|> >|> to rethrow the exception? (In most circumstances, doing so
|> >|> is probably a much better idea than just crashing via
|> >|> a call to abort().)
|> >
|> >1. How can it know what the exception was to rethrow it? Is a throw
|> >without an argument legal here? (I don't think so, but I'm not sure.)
|>
|> I was about to say that it must be legal -- this is precisely what Cline
|> and Lomow suggest in their FAQ book (FAQ #271). However:
|> >2. This behavior doesn't seem conform to the required behavior in
|> >18.6.1.2. I believe that when a user provided routine violates required
|> >behavior, undefined behavior results.
|> [Note: 18.6.1.2 in the April draft is now 18.6.2.2 in the Sept WP.]
|> It seems you're right, since the unexpected_handler isn't supposed to throw
|> the same (unexpected) exception again. Relevant section follows (from the
|> Sept WP; the April draft looks identical):
|> ---8<---8<----------------------------------------------------------------
|> Required behavior:
|> an unexpected_handler shall either throw an exception or terminate
|> execution of the program without returning to the caller. An unex-
|> pected_handler may perform any of the following:
|> --throw an exception that satisfies the exception specification;
|> --throw a bad_exception exception;
|> --call terminate();
|> --call either abort() or exit();
|> Default behavior:
|> The implementation's default unexpected_handler calls terminate().
|> ---8<---8<----------------------------------------------------------------
|> Is disallowing a rethrow deliberate, or something that could be relaxed to
|> allow rethrowing as Cline and Lomow suggest?
I would imagine that it must be deliberate. The whole purpose of
exception specifications is to offer some sort of a run-time guarantee
as to which exceptions may propagate out. Unexpected is called because
the program is attempting to violate that guarantee; if unexpected
re-throws the same exception, either it causes unexpected to be called
again (resulting in an endless loop), or the guarantee is violated (and
thus not a guarantee).
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/11/27 Raw View
Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
|> kanze@gabi-soft.fr (J. Kanze) writes:
|> >Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
|> >|> schuenem@informatik.tu-muenchen.de (Ulf Schuenemann) writes:
|> >
|> >|> >How about saying that dtors have an empty exception-specification
|> >|> >(either by default or always) ?
|> >
|> >|> How does that help?
|> >
|> >|> >Then there are 3 cases possible:
|> >|> >- The dtor causes no eception.
|> >|> >- The dtor catches all exceptions and continues - save,
|> >|> > but what happens to client-provided exception handling ?
|> >|> >- The dtor does not handle an exception that happend to be
|> >|> > be raised - unexpected() is called.
|> >
|> >|> Yes, and what if the programmer has defined unexpected()
|> >|> to rethrow the exception? (In most circumstances, doing so
|> >|> is probably a much better idea than just crashing via
|> >|> a call to abort().)
|> >
|> >1. How can it know what the exception was to rethrow it? Is a throw
|> >without an argument legal here? (I don't think so, but I'm not sure.)
|> Yes, a `throw;' statement is legal within an unexpected() handler.
|> 15.1/5-6 is quite clear:
|> | 5 A throw-expression with no operand rethrows the exception being han-
|> | dled without copying it.
|> |
|> | 6 The exception thrown is the one most recently caught and not finished.
|> | An exception is considered caught when initialization is complete for
|> | the formal parameter of the corresponding catch clause, or when termi-
|> | nate() or unexpected() is entered due to a throw. An exception is
|> | considered finished when the corresponding catch clause exits.
|> On entering unexpected(), the exception is considered handled, but not
|> finished, so `throw;' is fine.
|> The ARM contains an example of the use of `throw;' in an unexpected
|> handler (pages 365-366).
Great. So what does it mean. Suppose I write a function:
void f() throw() ...
What I'm trying to guarantee is that this function does not throw any
exceptions; this is a very important guarantee if exception safety is to
be taken seriously. In fact, of course, I've only guaranteed that it
won't throw any exceptions other than bad_exception (which is already a
serious compromise).
If unexpected does rethrow (or if it throws any exception other than
bad_exception), then I would expect unexpected to be called. If the
exception specifications are to mean anything, then the exception cannot
propagate out.
(IMHO, at least in the case of throw(), even bad_exception shouldn't
propagate out. Basically, allowing bad_exception to be an exception
means that even functions like the above can throw exceptions, which in
turn makes exception safety significantly harder; you must be prepared
to accept an exception at any time, since there is *no* way to ensure
that a given function never throws an exception.)
|> >2. This behavior doesn't seem conform to the required behavior in
|> >18.6.1.2. I believe that when a user provided routine violates required
|> >behavior, undefined behavior results.
|> Hmm, you're right - according to 18.6.1.2, an unexpected handler
|> must not throw the same exception. This would seem to imply that
|> `throw;' would be ok in an unexpected handler only if the exception didn't
|> escape, e.g.
|> void my_unexpected_handler() { try { throw; } catch(...) {} }
|> and also that the example in the ARM has undefined behaviour.
|> On the other hand, 15.5.2 definitely seems to assume that an
|> unexpected handler can throw an exception not in the exception
|> specification, and carefully describes the behaviour in that case.
|> So the draft is self-contradictory here. I think all you can really
|> say is that one of 15.5.2 and 18.6.1.2 is wrong.
I don't really think that this is a contradiction. 15.5 is speaking
about when the C++ language considers an exception finished (and thus,
*potentially* capable of being rethrown). This is necessary even when
the exception cannot actually be rethrown; it also defines when the
destructor of the exception is called. Thus, for example, the
constructor of an exception could save its this pointer in some global
variable; the `unexpected' function could then access the exception for
additional information. (And yes, I am aware that the current wording
of 15.5.2 doesn't say anything like this. But I think it is implicit in
the fact that a rethrow *must* throw the same object, not construct a
new one. It would be nice if there were some exact wording specifying
when the destructor of the exception will be called, however.)
The statements in 18.6.1.2 specify the semantic constraints of a
particular function. Thus, IMHO, the language per se allows rethrow at
this particular time, but the semantic constraints of the library do
not. (This is sort of like operator new() returning NULL. The
`language' per se certainly allows it, but the semantic constraints
specified in the library section do not. And while I agree that the
library is part of the language, its specification defines an additional
layer or level of constraint, distinct from the rest of the language.
IMHO, of course.)
In this regard, thus, I do not think that there is a contradiction,
although perhaps a footnote in 15.5.2, pointing out that the library
does introduce additional constraints, would be in order. (On the other
hand, if you start adding footnotes everywhere that a different section
may introduce additional constraints, you are likely to end up with more
footnotes than standard proper. I imagine that Andy Koenig and his
helpers have enough to keep them busy anyway.)
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/11/28 Raw View
herbs@interlog.com (Herb Sutter) writes:
>In article <494oog$hmf@gabi.gabi-soft.fr>,
> kanze@gabi-soft.fr (J. Kanze) wrote:
>>Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
>>|> schuenem@informatik.tu-muenchen.de (Ulf Schuenemann) writes:
>>|> >How about saying that dtors have an empty exception-specification
>>|> >(either by default or always) ?
>>
>>|> How does that help?
>
>I think he wants unexpected() to be called, rather than an inelegant
>terminate(), when a dtor throws during unwinding.
Why is calling unexpected() more elegant than calling terminate()?
By default, they will both do the same thing - call abort().
>>|> Yes, and what if the programmer has defined unexpected()
>>|> to rethrow the exception? (In most circumstances, doing so
>>|> is probably a much better idea than just crashing via
>>|> a call to abort().)
>>
>>1. How can it know what the exception was to rethrow it? Is a throw
>>without an argument legal here? (I don't think so, but I'm not sure.)
>
>I was about to say that it must be legal -- this is precisely what Cline and
>Lomow suggest in their FAQ book (FAQ #271).
It definitely *was* legal not so long ago.
>Is disallowing a rethrow deliberate, or something that could be relaxed to
>allow rethrowing as Cline and Lomow suggest?
The committee made a decision that exception specifications should be
fully enforced, in the sense that a function should never be allowed to
throw an exception not in its exception specification. This was a
change from the ARM, which allowed an unexpected handler to throw any
exception, and passed such exceptions up unchanged. But, rather than
force the program to always abort if a function throws an incorrect
exception, `bad_exception' was allowed as an escape hatch. The
committee decided that if an unexpected handler threw an unexpected
exception, and `bad_exception' was part of the function's exception
specification, then the thrown exception would get replaced with
bad_expection. This is reflected in the text of 15.5.2.
| 15.5.2 The unexpected() function [except.unexpected]
|
| 2 The unexpected() function shall not return, but it can throw (or re-
| throw) an exception. If it throws a new exception which is allowed by
| the exception specification which previously was violated, then the
| search for another handler will continue at the call of the function
| whose exception specification was violated. If it throws or rethrows
| an exception that the exception-specification does not
| allow then the following happens: if the exception-specification does
| not include the name of the predefined exception bad_exception then
| the function terminate() is called, otherwise the thrown exception is
| replaced by an implementation-defined object of the type bad_exception
| and the search for another handler will continue at the call of the
| function whose exception-specification was violated.
|
| 3 Thus, an exception-specification guarantees that only the listed
| exceptions will be thrown. If the exception-specification includes
| the name bad_exception then any exception not on the list may be
| replaced by bad_exception within the function unexpected().
However, as far as I can tell, there was some confusion as to where
unexpected exceptions would get replaced by bad_exception, because
the text in 18.6.2.1 [lib.unexpected.handler] seems to supplant this,
making everything but the first two sentences in the above quoted
text useless, because it implies that if an unexpected handler throws
or rethrows an exception that the exception-specification does not allow,
then the behaviour is undefined.
Ah! I think I understand now. 18.6.2.1 says than an unexpected
handler "may" do various things, which do not include throwing an
exception that the exception-specification does not allow. But it does
*not* say that it may not do anything else.
| 18.6.1.2 Type unexpected_handler [lib.unexpected.handler]
|
| typedef void (*unexpected_handler)();
|
| 1 The type of a handler function to be called by unexpected() when a
| function attempts to throw an exception not listed in its exception-
| specification.
| Required behavior:
| an unexpected_handler shall either throw an exception or terminate
| execution of the program without returning to the caller. An unex-
| pected_handler may perform any of the following:
|
| --throw an exception that satisfies the exception specification;
|
| --throw a bad_exception exception;
|
| --call terminate();
|
| --call either abort() or exit();
Note the difference between "shall" and "may" here.
I think the second sentence is effectively non-normative.
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
I will have little or no net access from Nov 30 until Dec 25.
Please email me a copy of any follow-ups.
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/11/28 Raw View
kanze@gabi-soft.fr (J. Kanze) writes:
>Fergus Henderson (fjh@munta.cs.mu.OZ.AU) wrote:
>|> The ARM contains an example of the use of `throw;' in an unexpected
>|> handler (pages 365-366).
>
>Great. So what does it mean. Suppose I write a function:
>
> void f() throw() ...
>
>What I'm trying to guarantee is that this function does not throw any
>exceptions; this is a very important guarantee if exception safety is to
>be taken seriously. In fact, of course, I've only guaranteed that it
>won't throw any exceptions other than bad_exception (which is already a
>serious compromise).
The guarantee didn't hold in ARM C++, but it *does* hold in DWP C++.
If you haven't explicitly listed bad_exception in the exception specification,
then an unexpected exception will result in a call to terminate() if
the unexpected handler rethrows the exception.
>(IMHO, at least in the case of throw(), even bad_exception shouldn't
>propagate out. Basically, allowing bad_exception to be an exception
>means that even functions like the above can throw exceptions, which in
>turn makes exception safety significantly harder; you must be prepared
>to accept an exception at any time, since there is *no* way to ensure
>that a given function never throws an exception.)
The committee agreed with you - bad_exception can't propagate out
unless explicitly listed. However, I still don't really agree with
your point about it making exception safety easier.
That depends on how you define exception safety. If you define
exception safety to mean "no resource leaks in the presence of exceptions",
then yes, you are right. But this simplistic version is not a good definition.
A better definition would be "no resource leaks or calls to abort()
in the presence of exceptions" - after all, a call to abort() is worse
than a resource leak, right? If you adopt this definition, then
exception safety is very difficult. A more realistic definition
of "reasonable exception safety" (rather than "perfect exception safety")
might be "no calls to abort(), and no resource leaks except in the
case of a bad_exception". This is safer than the simplistic
version, but still doesn't require you to worry about resource
leaks in the difficult cases. In other words, using
`foo() throw(bad_exception)' rather than `foo() throw()'
can result in better safety without any additional difficulty.
That's the theory, anyway. I've heard it said that many people
with real experience in using exception handling in large projects
don't agree, but I have not heard *why* they don't agree.
>|> So the draft is self-contradictory here. I think all you can really
>|> say is that one of 15.5.2 and 18.6.1.2 is wrong.
I've changed my interpretation since I wrote that. I now think that
we all just misread 18.6.1.2, taking it to imply more than it really said.
>I don't really think that this is a contradiction. 15.5 is speaking
>about when the C++ language considers an exception finished (and thus,
>*potentially* capable of being rethrown).
Um, I'm confused. Are you reading a different 15.5 to me?
My 15.5 [special functions] is about unexpected() and terminate().
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
I will have little or no net access from Nov 30 until Dec 25.
Please email me a copy of any follow-ups.
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: herbs@interlog.com (Herb Sutter)
Date: 1995/11/28 Raw View
In article <9533212.28401@mulga.cs.mu.OZ.AU>,
fjh@munta.cs.mu.OZ.AU (Fergus Henderson) wrote:
>>
>>if unexpected re-throws the same exception [...]
>
>No, neither of those cases holds. The reason that the guarnatee holds
>is that if an unexpected handler does throw an unexpected exception,
>the unexpected() function which called the handler will replace that
>exception with a `bad_exception' exception.
IOW, in an unexpected handler, "throw;" is the same as "throw bad_exception;"?
If true, this answers my concerns about Cline's/Lomow's recommendation.
Where is this documented?
Thanks,
Herb
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184
Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1995/11/29 Raw View
I find this view that specifying exceptions or
specifying NO exceptions is safety of any kind.
It is much more like the ASSERTs that are there
for debugging but are compiled out for the real
system, except there is no way to compile these
out. This means any library code that uses this
mechanism cannot be used in any high availability
application where staying up (possibly in a degraded
mode) is required behavior. There is no way
to firewall terminate/abort to a given place in the
application stack as far, as I can tell, and that
is bad. I strongly feel that the real reason
people want this stuff is that they are trying to
deal with the "only one exception at a time"
flawed design of the exception mechanism.
But it just does not cut it.
Also, how does terminate/abort fit the world
of operating environments? A language
standard needs to apply to all uses, not
just the application level.
Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: "nicolas (n.) chapados" <chapados@bnr.ca>
Date: 1995/11/20 Raw View
Distribution:
Michael Cook <mcook@cognex.com> wrote:
>>>>>> "SC" == Steve Clamage <clamage@Eng.sun.com> writes:
>
> SC> Apart from all of that, it is unlikely to be a good idea to throw
> SC> an exception from a destructor.
>
>Unfortunately, it's not easy in general to determine that some function being
>called from a destructor would not throw. And even if you could easily
>determine that no throwing could happen, could you be sure that that would
>always be true--regardless of what bit rot the program accumulates over the
>years?
>
>Ideally, the C++ language would be strong enough so that such caveats would
>not be necessary.
I do not very much like exception specifications with functions (the list of
exceptions that a function may throw), but this is one case where they would
be useful:
a destructor should restrict itself to calling functions with an *empty*
exception specification.
For example:
void f() throw ();
struct X {
~X()
{
f(); /* fine */
}
};
This ensures that the destructor never throws.
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: schuenem@informatik.tu-muenchen.de (Ulf Schuenemann)
Date: 1995/11/21 Raw View
In article <Pine.SGI.3.91-heb-2.02.951114164854.2393A-100000@arava>,
Anatoli Tubman <anatoli@ptc.com> writes:
[..]
|> Whether throwing from destructors shoud ever be considered by the C++ user
|> (as opposed to implementor) is a totally different question.
|> I believe that inability to destroy what you've just created
|> is a symptom of some very serious problem, for which terminate() is an
|> appropriate solution. However, standards should not prohibit
|> things only because they are ``bad style'' -- there must be other reasons.
How about saying that dtors have an empty exception-specification
(either by default or always) ?
Then there are 3 cases possible:
- The dtor causes no eception.
- The dtor catches all exceptions and continues - save,
but what happens to client-provided exception handling ?
- The dtor does not handle an exception that happend to be
be raised - unexpected() is called.
Ulf Schuenemann
--------------------------------------------------------------------
,_. Ulf Schuenemann
#, \ Fakultaet fuer Informatik, Technische Universitaet Muenchen, Germany.
| > email: schuenem@informatik.tu-muenchen.de
v=-< WWW: http://hphalle2.informatik.tu-muenchen.de/~schuenem/
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1995/11/17 Raw View
Anatoli Tubman (anatoli@ptc.com) wrote:
|> James Kanze <kanze@lts.sel.alcatel.de> writes:
|> > 1. Given:
|> > T a[ 5 ] ;
|> > When destructing the third element (for example), an exception is
|> > thrown. Are the remaining elements destructed? I would say yes
|>
|> Unfortunately, DWP is not clear enough in this area.
|> Here what it says (the numbers of statements are mine):
|>
|> (1) An object that is partially constructed will have destructors
|> executed only for its fully constructed sub-objects.
|> (2) Should a constructor for an element of an automatic array throw an
|> exception, only the constructed elements of that array will be
|> destroyed.
Does this only apply to automatic arrays. I thought it applied to all
arrays.
|> (3) If the object or array was allocated in a new-expression, the storage
|> occupied by that object is sometimes deleted also.
|> (Note that (3) does not appear in the ARM.)
|> I think that (2) should be rewritten, perhaps like this:
|> (2*) An object becomes fully constructed when its constructor returns
|> and remains such until a destructor for it is invoked.
IMHO, this is already covered in (1).
|> This covers the case covered by the present wording, and many others, for
|> which DWP makes no provisions -- without violating the spirit.
|> Also, (3) needs to be a little bit more specific. I think the following
|> will do well:
|> (3*) A delete-expression always deletes storage allocated for its
|> operand, regardless of any exceptions that might be thrown by any
|> of the destructors involved.
This is an entirely new point (4). (3) talks about exceptions in
new-expressions; here we talk about exceptions in delete-expressions.
Consider the following:
auto_ptr< T >* pp = new auto_ptr< T >[ 3 ] ;
// ..
delete [] pp ;
According to the standard, this will result in calling the destructors
of auto_ptr on pp[ 2 ], pp[ 1 ] and pp[ 0 ], in that order, then calling
operator delete[] on the resulting raw memory. The destructors for the
auto_ptr's will delete the object they point to.
Now suppose that T::~T() throws an exception when destructing pp[ 1 ].
If the implementation does not continue by destructing pp[ 0 ] and
calling operator delete, there is *no* way the user can. Even if the
user traps the exception, he cannot call ``delete [] pp'' a second time,
since this would cause the destructor of the already destructed pp[ 2 ]
to be called. He could not even attempt to do the job by hand, calling
explicitly the remaining destructors, and then operator delete[], for
several reasons:
1. He has, a priori, no way of knowing how many of the objects have
already been destructed.
2. Even if he did, he cannot call the destructor on the auto_ptr element
in which the exception occurred. So the memory that auto_ptr pointed to
is lost.
3. Even solving this problem, he cannot call operator delete[] directly,
since it is not guaranteed that the address returned by operator new[]
is the same as that returned by the new expression (and in general, in
the above case, it isn't).
|> If an implementation does not impose an added cost to code that does not
|> catch or throw exceptions, it can be easily modified to comply with the
|> above rules and still add no overhead to such code.
|> Whether throwing from destructors shoud ever be considered by the C++ user
|> (as opposed to implementor) is a totally different question.
|> I believe that inability to destroy what you've just created
|> is a symptom of some very serious problem, for which terminate() is an
|> appropriate solution. However, standards should not prohibit
|> things only because they are ``bad style'' -- there must be other reasons.
Agreed. In the internet protocol suite, there is a ``robustness
principle'' which states: "Be liberal in what you accept, and
conservative in what you send." I like to apply this generally: a user
should not allow exceptions to escape from destructors, but the
implementaion (and the language definition) should work when the case
occurs. (Note that unless the implementation does go on to free the
memory, auto_ptr is not exception safe under its current definition.)
--
James Kanze (+33) 88 14 49 00 email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils, itudes et rialisations en logiciel orienti objet --
-- A la recherche d'une activiti dans une region francophone
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]