Don't expect class destructors to be called at all by the GC

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Dec 21 18:20:19 UTC 2017


On Thu, Dec 21, 2017 at 06:50:44AM +0000, Mike Parker via Digitalmars-d-learn wrote:
[...]
> I just don't even bother with class destructors. Without a guarantee
> that they can run and without any sort of deterministic behavior, it's
> really not appropriate to refer to them as destructors and they're
> about as useful as Java finalizers, which means not at all. In order
> to make them less error prone, we need to separate the concept of
> destruction from finalization and allow both destructors and
> finalizers. That's what I've taken to doing manually, by implementing
> a `terminate` function in my classes that I either call directly or
> via a ref-counted templated struct called Terminator.

I recently ran into this problem while using Adam Ruppe's lightweight
SQLite binding (arsd/sqlite.d). Originally, I kept an open database
handle (which is a class instance) throughout the lifetime of the
program; in this case, I could just use a scoped reference and it would
ensure the DB is closed when the handle went out of scope, just what I
want.  But as my code developed, I began to need to cache multiple DB
handles for performance, and scope no longer helps me there. At first I
thought, no problem, the GC would handle this for me. Right?

Wrong. Even calling GC.collect directly did not guarantee the DB handle
was closed at the right time.  This may have been a bug in my code that
left dangling references to it, or perhaps the array of Database handles
was still scanned through by the GC even though the only remaining array
slice has a shorter length. Whatever the reason was, it left me with the
very unpleasant prospect of silently accumulating file descriptor leaks.

I ended up calling .destroy on the class instance explicitly just so the
destructor would run at the right time, right before nulling the
reference so that the GC would collect the memory.

This makes using classes in D an even dimmer prospect than it already
generally is (nowadays, and I don't seem to be the only one, I prefer to
just use structs and templates instead of runtime polymorphism, where
possible).  When the scoped destruction of structs isn't an option,
RefCounted!T seems to be a less evil alternative than an unreliable
class dtor. :-/


T

-- 
MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs


More information about the Digitalmars-d-learn mailing list