Thread View: comp.std.c++
7 messages
7 total messages
Started by Scott Meyers
Sat, 18 Nov 1995 03:49
Exceptions in derived class destructors
Author: Scott Meyers
Date: Sat, 18 Nov 1995 03:49
Date: Sat, 18 Nov 1995 03:49
50 lines
1809 bytes
1809 bytes
I posted this a while ago as part of a larger posting, but nobody ever
responded. I'm reposting it as a separate question in hope of gaining
insight into the proper behavior of destructors when exceptions are thrown:
If a derived class destructor throws an exception, do member and base
class destructors still get called? Consider this program:
#include <iostream.h>
class M {
public:
~M() { cout << "M destructor\n"; }
};
class B {
M m;
public:
~B() { cout << "B destructor\n"; }
};
class D: public B {
M m;
public:
~D() { cout << "Starting D destructor\n";
throw "Ouch!";
cout << "Ending D destructor\n";
}
};
int main()
{
D d;
return 0;
}
When d is destroyed, D's destructor throws. Are destructors
nevertheless called for d.D::m, the B part of d, and d.B::m? My feeling is
the answer should be no, in the same way that the remainder of D's
destructor is not executed after the throw. Different compilers do
different things, however. Who knows what is supposed to happen?
Scott
---
[ 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. ]
Re: Exceptions in derived class destructors
Author: Steve Clamage
Date: Sun, 19 Nov 1995 02:59
Date: Sun, 19 Nov 1995 02:59
39 lines
2253 bytes
2253 bytes
smeyers@netcom.com (Scott Meyers) writes: >I posted this a while ago as part of a larger posting, but nobody ever >responded. I'm reposting it as a separate question in hope of gaining >insight into the proper behavior of destructors when exceptions are thrown: > ... > When d is destroyed, D's destructor throws. Are destructors > nevertheless called for d.D::m, the B part of d, and d.B::m? My feeling is > the answer should be no, ... The draft says that when an exception is thrown, control is transferred to the handler for that exception, or to the terminate function if there is no handler. I don't see how to interpret that to allow any additional processing if the destructor exits via an exception. The special cases of operator new or a constructor exiting via an exception as part of a new-expression has some additional handling, but I don't see any special cases for destructors. In other words, the base-class destructors should not be run. LOTS of things about exceptions have needed clarification or changes in the rules, so it wouldn't be surprising to see variation in compiler behavior right now. Apart from all of that, it is unlikely to be a good idea to throw an exception from a destructor. It would be safer and less likely to leave the program in an unknown state to use some other error- reporting method for destructors. -- Steve Clamage, stephen.clamage@eng.sun.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. ]
Re: Exceptions in derived class destructors
Author: Steve Clamage
Date: Mon, 20 Nov 1995 16:35
Date: Mon, 20 Nov 1995 16:35
77 lines
3615 bytes
3615 bytes
In article <smeyersDI7uqr.9vt@netcom.com> smeyers@netcom.com (Scott
Meyers) writes:
|> I posted this a while ago as part of a larger posting, but nobody ever
|> responded. I'm reposting it as a separate question in hope of gaining
|> insight into the proper behavior of destructors when exceptions are thrown:
|> If a derived class destructor throws an exception, do member and base
|> class destructors still get called? Consider this program:
|> #include <iostream.h>
|> class M {
|> public:
|> ~M() { cout << "M destructor\n"; }
|> };
|> class B {
|> M m;
|> public:
|> ~B() { cout << "B destructor\n"; }
|> };
|> class D: public B {
|> M m;
|> public:
|> ~D() { cout << "Starting D destructor\n";
|> throw "Ouch!";
|> cout << "Ending D destructor\n";
|> }
|> };
|> int main()
|> {
|> D d;
|> return 0;
|> }
|> When d is destroyed, D's destructor throws. Are destructors
|> nevertheless called for d.D::m, the B part of d, and d.B::m? My feeling is
|> the answer should be no, in the same way that the remainder of D's
|> destructor is not executed after the throw. Different compilers do
|> different things, however. Who knows what is supposed to happen?
Supposed to, according to the standard, or supposed to, according to
what is necessary for the program to work.
I've not found any wording in the current draft which seems to cover
the fall of an exception in a destructor (but it's quite possible that
I haven't looked in the right places). The closest I can come is in
section 15.2, paragraph 2: "An object that is partially constructed
will have destructors executed only for its fully constructed
sub-objects." These seems to only be talking about exceptions in
constructors, however, although one could argue that a destructor
`unconstructs' the corresponding part of the object, which results in
a partially constructed object.
From necessity, the destructors *must* be called by the
implementation, because there is *no* way for the application to call
them. In this regard, the problem is exactly the same as in the case
of an array; I have already posted why the user cannot finish cleaning
up the array. To see why, suppose, in your example, that the
destructor of B throws the exception (and not the destructor of D).
How can the user possibly call the destructor of B::m, supposing he
catches the exception?
--
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. ]
Re: Exceptions in derived class destructors
Author: Fergus Henderson
Date: Tue, 21 Nov 1995 15:46
Date: Tue, 21 Nov 1995 15:46
39 lines
2585 bytes
2585 bytes
smeyers@netcom.com (Scott Meyers) writes: >I posted this a while ago as part of a larger posting, but nobody ever >responded. I'm reposting it as a separate question in hope of gaining >insight into the proper behavior of destructors when exceptions are thrown: > > If a derived class destructor throws an exception, do member and base > class destructors still get called? If you are asking about what the current working paper says, I'm not sure off-hand. If you are asking about what the working paper *should* say, then I think the answer should be yes, member and base class destructors should still get called. Otherwise the destructor would have to catch execptions and manually destroy the bases and members before rethrowing to avoid resource leaks. This would be extremely tedious coding, and would be extremely difficult - probably totally impractical - in the case of virtual inheritence. > My feeling is > the answer should be no, in the same way that the remainder of D's > destructor is not executed after the throw. I disagree. The answer should be yes, in the same way that bases and members are destroyed if an exception occurs in the constructor. Any class which attempts to manage more than one resource must be careful do its own recovery if an exception occurs after constructing or destroying a subset of those resources. But for a class which merely aggregates different resources which are managed by members or base classes, the author of that class should not have to worry about exception handling. -- Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3 --- [ 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. ]
Re: Exceptions in derived class destructors
Author: Fergus Henderson
Date: Tue, 21 Nov 1995 15:47
Date: Tue, 21 Nov 1995 15:47
39 lines
2506 bytes
2506 bytes
smeyers@netcom.com (Scott Meyers) writes: >I posted this a while ago as part of a larger posting, but nobody ever >responded. I'm reposting it as a separate question in hope of gaining >insight into the proper behavior of destructors when exceptions are thrown: > > If a derived class destructor throws an exception, do member and base > class destructors still get called? If you are asking about what the current working paper says, I'm not sure off-hand. If you are asking about what the working paper *should* say, then I think the answer should be yes, member and base class destructors should still get called. Otherwise the destructor would have to catch execptions and manually destroy the bases and members before rethrowing to avoid resource leaks. This would be extremely tedious coding, and would be extremely difficult - probably totally impractical - in the case of virtual inheritence. > My feeling is > the answer should be no, in the same way that the remainder of D's > destructor is not executed after the throw. I disagree. The answer should be yes, in the same way that bases and members are destroyed if an exception occurs in the constructor. Any class which attempts to manage more than one resource must be careful do its own recovery if an exception occurs after constructing or destroying a subset of those resources. But for a class which merely aggregates different resources which are managed by members or base classes, the author of that class should not have to worry about exception handling. -- Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3 --- [ 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. ]
Re: Exceptions in derived class destructors
Author: James Kanze US/ESC 60/3/141 #407...
Date: Tue, 21 Nov 1995 16:00
Date: Tue, 21 Nov 1995 16:00
121 lines
6028 bytes
6028 bytes
In article <48m6b8$2ll@engnews1.eng.sun.com> clamage@Eng.sun.com
(Steve Clamage) writes:
|> smeyers@netcom.com (Scott Meyers) writes:
|> >I posted this a while ago as part of a larger posting, but nobody ever
|> >responded. I'm reposting it as a separate question in hope of gaining
|> >insight into the proper behavior of destructors when exceptions are thrown:
|> > ...
|> > When d is destroyed, D's destructor throws. Are destructors
|> > nevertheless called for d.D::m, the B part of d, and d.B::m? My feeling is
|> > the answer should be no, ...
|> The draft says that when an exception is thrown, control is transferred
|> to the handler for that exception, or to the terminate function if
|> there is no handler.
|> I don't see how to interpret that to allow any additional processing if
|> the destructor exits via an exception.
The draft requires unwinding of the stack. This is definitly
additional processing.
|> The special cases of operator new or a constructor exiting via an
|> exception as part of a new-expression has some additional handling,
|> but I don't see any special cases for destructors.
There are two separate issues:
In 15.2, there is no mention of operator new or constructors. There
is a statement as to how "partially constructed objects" are handled.
This would seem relevant to Scott's question: since a destructor
"unconstructs" an object, it would seem a reasonable interpretation,
if not the most obvious, that an object whose destructor has been
called is partially constructed. (If this is actually the desired
interpretation, then I think it would be better if it were made a
little bit more explicit.)
With regards to actually deleting the memory when the exception occurs
during a delete expression: as you say, the standard makes no special
case, and (as I have pointed out in other postings) the user has no
way of deleting it either. In this case, the present wording of the
standard imposes a memory leak.
|> In other words, the base-class destructors should not be run. LOTS
|> of things about exceptions have needed clarification or changes
|> in the rules, so it wouldn't be surprising to see variation in
|> compiler behavior right now.
More generally, the status with regards to destructors/delete reminds
me of the status in the ARM with regards to new expressions. It
wasn't quite clear what was intended, but the consequences of a strict
interpretation (the implementation did not free the memory) simply
made it impossible to write a program without memory leaks. Because
of this, no reasonable implementation implemented this interpretation.
Now that the problem has been recognized in destructors/delete, I
would not expect a reasonable implementation to implement exactly what
is stated either, but rather that it call the destructors for the yet
fully constructed objects, and delete the memory. The difference is,
of course, unlike the case when the problems with operator new were
recognized, most implementations already have exceptions, and handle
this case in various ways.
|> Apart from all of that, it is unlikely to be a good idea to throw
|> an exception from a destructor. It would be safer and less likely
|> to leave the program in an unknown state to use some other error-
|> reporting method for destructors.
I agree.
I see three possible solutions that the committee could adopt:
1. Define detailed special cases like is currently done for exceptions
in a new expression, requiring the implementation to destruct all
sub-objects, and actually call operator delete() if the exception
occurs in a delete expression. (Why not doing this doesn't work has
been described in another posting.)
2. Declare that destructors all have an implicit "throw()"
specification, which cannot be changed by the programmer. An
exception which propagates out of a destructor thus results in a call
to unexpected. Alternatively, it could simply say that an exception
which propagates out of a destructor always calls terminate, rather
than this being a special case when unwinding the stack due to a
previous exception.
3. Declare that an exception which propagates out of a destructor is
undefined behavior, and leave it up to the implementations whether
they want to do anything about it or not.
Given the time constraints, I slightly favor 2, although 1 would be
quite acceptable if the committee can find time to work out all of the
details. I would rather not see 3.
BTW: it is rather simple to avoid the consequences of an exception
propagating out of a destructor: just encapsulate the destructor in a
function try block, e.g.:
T::~T() try
{
// ...
}
catch (...)
{
}
Any exception which propagates out to the destructor is just ignored.
--
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. ]
Re: Exceptions in derived class destructors
Author: Fergus Henderson
Date: Thu, 23 Nov 1995 15:32
Date: Thu, 23 Nov 1995 15:32
55 lines
2894 bytes
2894 bytes
clamage@Eng.sun.com (Steve Clamage) writes: >smeyers@netcom.com (Scott Meyers) writes: > >> When d is destroyed, D's destructor throws. Are destructors >> nevertheless called for d.D::m, the B part of d, and d.B::m? My feeling is >> the answer should be no, ... > >The draft says that when an exception is thrown, control is transferred >to the handler for that exception, or to the terminate function if >there is no handler. > >I don't see how to interpret that to allow any additional processing if >the destructor exits via an exception. Yes, it does say that in 15.1, but it also says in 15.2 that as control passes between those two points, stack unwinding happens - destructors get called. Additional processing most definitely does occur! >The special cases of operator new or a constructor exiting via an >exception as part of a new-expression has some additional handling, >but I don't see any special cases for destructors. It's not a special case, it is just the usual case of stack unwinding. See 15.2: | 15.2 Constructors and destructors [except.ctor] | | 1 As control passes from a throw-point to a handler, destructors are | invoked for all automatic objects constructed since the try block was | entered. Note - it does NOT say "for all automatic *complete* objects". Note that according to the definition in 1.6 [intro.object], a sub-object is an object. So it must include sub-objects. In other words, according to the above quote from the April draft, base class and member sub-objects that have been constructed since the try block was entered should be destroyed. Certainly the draft could be clearer - but it *is* only a draft. >Apart from all of that, it is unlikely to be a good idea to throw >an exception from a destructor. It would be safer and less likely >to leave the program in an unknown state to use some other error- >reporting method for destructors. Agreed. -- Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3 [ 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. ]
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads