mikem@otc.oz (Mike Mowbray) (04/08/88)
Since there's heaps of talk goign around about exception-handling ....
We've heard about how when an exception is raised, and a function context
is resumed further back in the stack, appropriate destructors must first
be called for stuff inside intermediate functions which will now not be
returned through.
Problem: this means that all classes must be designed so that their
destructors are callable at any instant and behave correctly, even
if you're in the middle of a member function which is adjusting
the internal configuration of the class. (For example, a member
function which calls another function in which an exception gets
raised).
In general, it would seem very demanding to require that destructors for
non-trivial classes be callable at any moment. The destructor writer must
anticipate every possible mis-configuration of the class's internal
structure.
Maybe it's sufficient to adopt a general rule: "In your destructor, assume
that everything is probably corrupted". But then this must also apply to
member functions, since destructors might call them to do part of the
cleanup job. In any case, this is obviously highly error-prone.
The alternative is to ensure that a member function never calls something
else unless the class is already perfectly consistent. But how could an
automated tool assist in detecting this? Maybe the programmer could define
assertions for the class, and the compiler would arrange for them to be
checked before calling any function from within a member function. Sounds
dreadful, doesn't it. Maybe it would be sufficient for the mechanism that
generates the automatic call of destructors to arrange for the assertions
to be checked. But what do you do if the assertion fails?
Another problem area: what if a destructor executes normally to some point,
and then calls a function in which an exeption gets raised, which invokes
the same destructor again in the attempt to clean up properly...?
Thoughts anyone?
Mike Mowbray
Systems Development
|||| OTC ||
PHONE (02) 287-4104 ACSnet: mikem@otc.oz
FAX (02) 287-4990 UUCP: {uunet,mcvax}!otc.oz!mikem
SNAIL OTC, GPO Box 7000 CSNET: mikem@otc.oz.au
Sydney 2001, Australia ARPA: mikem@otc.oz.aushapiro@blueberry.inria.fr (Marc Shapiro) (04/19/88)
In article <352@otc.oz> mikem@otc.oz (Mike Mowbray) writes: >Since there's heaps of talk goign around about exception-handling .... > [...] >Problem: this means that all classes must be designed so that their > destructors are callable at any instant and behave correctly, even > if you're in the middle of a member function which is adjusting > the internal configuration of the class. (For example, a member > function which calls another function in which an exception gets > raised). > >In general, it would seem very demanding to require that destructors for >non-trivial classes be callable at any moment. The destructor writer must >anticipate every possible mis-configuration of the class's internal >structure. >[...] >Another problem area: what if a destructor executes normally to some point, >and then calls a function in which an exeption gets raised, which invokes >the same destructor again in the attempt to clean up properly...? I agree totally with these points. I would also like to add that you are never assured that the destructor for a certain object will actually be called: you might exit, abort, call a non-returning function, or just forget to call delete. Therefore I think an important programming principle is: NEVER TRUST A DESTRUCTOR TO BE CALLED. (Does Unix trust you to "close()" all your files cleanly? No way.) Corollary: NEVER DO ANYTHING IMPORTANT IN A DESTRUCTOR. The only sorts of things a destructor should do are "benevolent side-effects", i.e. things which can benefit performance but won't be a mistake if not performed, e.g. freeing memory. Suppose for instance you have an application which creates many windows. For each window the application allocates a window object. The window object constructor tells the window manager to reserve space for it, and the desctructor tells the window manager to close (i.e. erase) the window. Now what if this application gets killed: the window manager must detect this and delete the corresponding windows. Conclusion: it's not worthwile for the window-object destructors to close windows, it's just duplicating work that the manager has to do anyway. (If you want windows to pop up and disappear, add a window::close() operation, independent of the destructor). The final problem is that the window manager needs a way to detect that that the application went away. This is not easy in today's operating systems. Marc Shapiro INRIA, B.P. 105, 78153 Le Chesnay Cedex, France. Tel.: +33 (1) 39-63-53-25 e-mail: shapiro@inria.inria.fr or: ...!mcvax!inria!shapiro Marc Shapiro INRIA, B.P. 105, 78153 Le Chesnay Cedex, France. Tel.: +33 (1) 39-63-53-25 e-mail: shapiro@inria.inria.fr or: ...!mcvax!inria!shapiro
jima@hplsla.HP.COM ( Jim Adcock) (04/21/88)
In general, it seems to me your statements are true, iff one requires that "exception handling" be able to handle any kind of failure, at any point of time in the execution of the software. In many cases, you have a better knowledge of where and when to expect various kinds of errors to crop up, in which case possibly one could pragmatically apply easier requirements to one's error handling, recovery, and associated destructor schemes. I don't believe "exception handling" is going to magically "fix" all the software/hardware errors that can crop up in a serious-sized software project. So I believe an "exception handling" scheme that can improve the overall reliability of the software product by a factor of maybe 10X-100X or better would be quite acceptible.