On Tuesday, 11 November 2014 at 22:31:17 UTC, Maxime
Chevalier-Boisvert wrote:
I have a situation where I have a VM (virtual machine) object,
and several GCRoot (garbage collector root objects). The
GCRoots are structs and will "register" themselves into a
linked list belonging to the VM. I've made it so they
unregister themselves in their destructor. This works perfectly
well for GC roots which are on the stack.
However, recently, I ran into a case where I need GCRoots which
are not on the stack. This is where things broke down. The VM
object got destroyed before the GCRoots, and when these tried
to unregister themselves, they accessed memory which had
already been reclaimed (the dead VM). What I want to know is:
what guarantees can I expect from destructor behavior?
I was thinking that when the VM gets destroyed, it could
unregister all of its GCRoots at once. Then, when these are
destroyed, they wouldn't try to touch the VM object. However,
this only works if I can assume that the GC will first call the
destructor on an object, then free the object, that this is
done in a predictable order. Am I on the right track, or do I
need to rethink this?
Could this work?
class VM {
List gcRootList;
this() {
gcRootList.add(GCRoot.init);
..
to
class VM {
static List[VM*] _gcRootLists;
List* gcRootList;
this() {
_gcRootLists[&this] = List.init;
gcRootList = &_gcRootLists[&this];
gcRootList.add(GCRoot.init);
..
~this() {
_gcRootLists.remove(&this);
..