Destructor nonsense on dlang.org
Mehrdad
wfunction at hotmail.com
Thu May 24 22:07:46 PDT 2012
On Thursday, 24 May 2012 at 16:06:23 UTC, Andrei Alexandrescu
wrote:
> It does matter because a destructor may use an object that has
> just been destroyed.
>
> Andrei
Andrei: .NET has this exact problem, and handles it pretty well.
There are two types of "Dispose()": manual and automatic.
Whenever you're wrapping some unmanaged resource (e.g. file
handle), you wrap it inside some managed object (e.g.
SafeFileHandle).
Then you embed _that_ resource in the actual object you want
(e.g. FileStream).
Now, there are two ways a FileStream can get destroyed:
1. Through a manual call to FileStream.Dispose(). In this case,
all embedded objects (e.g. SafeFileHandle) are *guaranteed* to be
valid, so we simply flush the file and call
SafeFileHandle.Dispose() to dispose of the managed resources, and
then dispose of all the unmanaged resources (which are primitive
fields, guaranteed to be accessible). Furthermore, the object
suppresses its own finalizer.
2. Through a garbage-collected call to ~FileStream(). In this
case, the managed resources such as SafeFileHandle will be (or is
already) destroyed SEPARATELY, and so we do _NOT_ access them. We
ONLY dispose of the unmanaged resources, if any, and let the
managed resources take care of themselves.
It's a pretty well-defined sequence, and it works well in
practice.
(Of course, you don't actually _need_ this double-indirection
here: You could instead just wrap the unmanaged resource
manually, and do everything in FileStream. The reason for the
double-indirection is something slightly unrelated. I was just
explaining how to take care of the managed resource disposal
problem that you mentioned.)
You could point out that, in this case, the FileStream doesn't
flush its buffers before the file handle is destroyed, if the GC
collects the object.
That problem is solvable in two ways, although .NET simply chose
to not worry about it, as far as I know:
1. Simply wrap the handle inside FileStream. Since it will be
unmanaged, you can access it during disposal.
2. If that isn't possible, keep a _strong_, *unmanaged* reference
to your _managed_ SafeFileHandle object. (This is accomplished
through acquiring a cookie from the GC.) Because of this,
SafeFileHandle will NOT be destroyed before FileStream. You can
then use this fact to access SafeFileHandle inside FileStream's
finalizer, through the unmanaged (but safe) cookie.
tl;dr: It's a completely solved problem in .NET; there really
shouldn't be any issues with it in D either.
More information about the Digitalmars-d
mailing list