Can I remove an element from a global associative array from within a class destructor?

Jonathan M Davis newsgroup.d at
Sat Aug 3 05:33:05 UTC 2019

On Friday, August 2, 2019 5:13:10 PM MDT realhet via Digitalmars-d-learn 
> Hi,
> I tried to make some resource statistict for my OpenGL Buffer
> objects:
> //here are the things that hold the statistics.
> private __gshared{ size_t[int] textureSizeMap, bufferSizeMap; }
> struct GLCounters{
>    int programs, shaders, textures, buffers;
>    size_t textureSize, bufferSize;
> }
> __gshared GLCounters glCounters;
> ...
> //And this is the buffer creation.
> int genBuffer(size_t size){
>    int res; glGenBuffers (1, &res); glChk;
>    glCounters.buffers ++;
>    glCounters.bufferSize  += size;
>    bufferSizeMap [res] = size;
>    writefln("buffer allocated %d %d", res, size);
>    return res;
> }
> //Finally, this is the deallocation. If it is called from the GC
> (when it destroys a class), it has a big chance to throw an
> Invalid Memory Operation exception.
> void deleteBuffer (int handle){
>    if(!handle) return;
>    glDeleteBuffers (1, &handle); glChk;
>    glCounters.buffers --;
>    glCounters.bufferSize  -= bufferSizeMap [handle];
>    writefln("buffer deallocated %d %d", handle, bufferSizeMap
> [handle]);
>    bufferSizeMap.remove(handle); <- this is the problematic part.
> }
> --------------------------------------------
> Today I read the documentation about structs, unions and classes,
> but I haven't find any restrictions for the ~this() destructors.
> Is there some extra rules regarding the GC and what I must not do
> in the destructors?
> I think the destructor always called in the same thread where the
> instance was created. This can't be the case.
> But what I can guess is: The GC makes a collection and calls my
> destructor and inside I do something and the GC calls a
> collection again recursively. But it seems a bit crazy, so I
> think it's not the case :D
> Please help me solve this!
> *I'm using LDC 1.6.0 Win64

As I understand it, you can't do much of anything that involves the GC
inside a destructor that's being run as a finalizer by the GC (as is almost
always the case with classes). Structs or classes on the stack (which for
classes requires something like scope) don't have that problem, because
they're not being run by the GC. But if a struct or class is on the GC heap,
then attempting to allocate or deallocate GC resources doesn't work, because
the destructor/finalizer runs when the GC is doing a collection. Even trying
to use other objects that are on the GC heap from a finalizer is not a
allowed, because there is no guarantee about the order that the objects are
collected (otherwise, cyclical references would be a big problem), meaning
that references in the finalizer could refer to objects that have already
been destroyed and their memory freed.

Basically, destructors/finalizers for anything on the GC heap are just for
cleaning up non-GC-allocated resources.

- Jonathan M Davis

More information about the Digitalmars-d-learn mailing list