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.

Reply via email to