On 7 mar, 22:56, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:
> > On 7 mar, 17:43, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * James Kanze:
> >>> On Mar 6, 6:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >>>> * unix...@gmail.com:
> >>> [...]
> >>>> That's known as a zombie object, and they're a common problem
> >>>> in garbage-collection based languages like Java and C# that do
> >>>> not have automated deterministic destruction.
> >>> You've got me there. How does the lack of automated
> >>> deterministic destruction relate to zombie objects.
> >> You have known that earlier...
> >> When you don't have automatic deterministic destruction, and
> >> you have some resource to release, you have to implement some
> >> kind of manual cleanup, e.g. a member function destroy()
> >> available to client code.
> > I think we're talking about a different context. I don't see
> > the relevance with regards to constructors or zombie objects
> > here.
> See below, or earlier in the thread, keeping in mind that a
> constructor's main job is (usually) to establish the class
> invariant.
Right. The constructor's. Deterministic destruction and
garbage collection aren't really relevant here: the question is
what happens when for some reason the the constructor cannot
establish the invariants. If the object "exists" anyway (or
perhaps more correctly, in C++ standardese, if there is an
lvalue expression which can refer to it), then you have a
zombie. Zombies can easily be objects with no destructor
(although I suspect that the case is rare in standard C++), and
Zombieism affects local objects (on stack) just like any others;
dynamic allocation is not necessary for zombies to exist.
In older C++, before exceptions were introduced, zombies
couldn't be avoided. If you wrote something like:
{
C obj ;
// ...
}
there was no way to avoid obj "existing". So you had to create
a zombie state, require the client code to check it, verify it
on each access, etc. The key to not having zombies is
exceptions (and you can avoid them just as well in Java as in
C++).
> Or perhaps read Bjarne's article that the OP was referring to.
Bjarne's article didn't really mention zombies. It talked about
cleaning up in the destructor, before (or as a result of)
throwing the exception. If I understood it correctly, Bjarne
didn't consider the possibility of having a zombie; he only
talked about what happens when reporting an error via an
exception.
Again, the problem is common to all languages which have
exceptions. The tools available to solve the problem do vary
from one language to the next---in Java, you must use a try
block; in C++, you have the choice between a try block and a
subobject with a destructor, which will be called once the
subobject has been fully constructed.
Having a choice is, of course, a good thing. But the choice the
programmer makes isn't that critical here---either way, he's
cleaned up. (I'm talking here about explicitly creating a class
which has no other reason d'être but to exploit this behavior of
destructors. Obviously, if the class you are writing is a
client of another, existing class, then that class should take
care of all necessary clean-up in its destructor, and the fact
that you, as a client, don't have to write explicit try/catch
blocks is a definite advantage.)
> This all hangs together.
I still don't see any real relationship. Zombie objects are a
result of design choices (or in pre-exception days, the lack of
a possible choice) concerning the constructor. Deterministic
destruction solves a different set of problems, and garbage
collection is yet a third issue, orthogonal to the other two.
> > (In practice, the destroy() function in C++ is the
> > destructor. But that's not the issue here.)
> >> There's no way to guarantee that destroy() is called exactly
> >> once or only when the object will no longer be used. Worse, to
> >> support code that forgets to call destroy(), it's not uncommon
> >> to also do cleanup in a finalize() function that may be called
> >> by the garbage collection. And a common solution is to let
> >> the cleanup code note in the object's state that it's
> >> destroyed, a zombie.
> > Now you've lost me completely. I can't make heads or tails
> > out of the above---it seems to mix any number of separate
> > concepts.
> Yes, this all hangs together.
How? Before C++ had exceptions, zombie classes were a fact of
life. Even when no dynamic allocation was involved, and in a
few odd cases, when no resources at all were involved.
> >> An example of this monstrosity (googled this up now just for
> >> your convenience):
> >> <url:http://www.javapractices.com/topic/TopicAction.do?Id=43>.
> >> Problem with that example: abstracting a resource that can
> >> become invalid on its own, such as a file or db connection, is
> >> inherently difficult, so that the complexity in that zombie
> >> solution doesn't quite properly illustrate the evils of
> >> zombies.
> > OK. We agree there. But my impression is that the problem
> > being addressed in all this is that Java doesn't have
> > destructors, so you need a finally block.
> That's one problem that can lead to zombies.
How? This is one case where Java and C++ behave almost
identically:
{
MyClass obj = new MyClass ;
// ...
}
in Java behaves exactly like:
{
MyClass obj ;
// ...
}
in C++. If the constructor exits via an exception, there is no
way of accessing the non-existing (or invalid) object. Thus, no
zombie.
--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34