Derelict SFML destructor crashes

Mike Parker aldacron at gmail.com
Mon Dec 17 00:58:00 PST 2012


On Monday, 17 December 2012 at 08:23:02 UTC, Jeremy DeHaan wrote:
> I am somewhat confused by some things that are being talked 
> about in this thread.
>
> Mike Parker said that this Image is handled by GC. Would that 
> mean that any class members are handled by the GC too? If so, 
> wouldn't the sfImage* be collected by the GC?

Any class members that are allocated on the D heap, sure. But the 
memory for sfImage is allocated by sfml outside of the D garbage 
collector's heap. The GC knows nothing about it. The GC can only 
free the memory it controls. When you allocate memory from a C 
library, you are responsible for cleaning it up. But, you cannot 
rely on a class destructor to do this for you. There is 
absolutely no guarantee about when or if class destructors will 
be run, or in what order, during program execution. So relying on 
a destructor is totally nondeterministic.

And when using Derelict, if you try to call a bound library in a 
destructor, but the object is not released until the GC cleans up 
at program exit, you will always get a crash because Derelict 
will have already unloaded

>
> If not, and you DO need to manually delete the pointer, is 
> there anything wrong with something like:
>
> ~this
> {
>     destroy(image);
> }
>

See above. You should never do this sort of thing in a destructor.

>
> I am just thinking that it would suck to have to manually call 
> destroy/delete on each object before exiting main. I tested 
> this, and I didn't get any memory errors, so I can assume it is 
> working? I did get an error if I used delete image, however. 
> What's the difference between the two?

I'm not quite sure what you are referring to when you say, "I 
tested this." Which? Freeing the image in a destructor?

I always clean up manually. When making a game in D, this is the 
approach I take.
==================
module mygame;
private void init()
{
// Throw Error on failure
DerelictFoo.load();
graphicsInit();
audioInit();
...
}

private void term()
{
// Release all resources here
...
audioTerm();
graphicsTerm();
}

void main(string[] args)
{
scope(exit) term();
init();
gameLoop();
}
=================

Then in each subsystem, there's always some sort of 
list/manager/registry that managers different objects. Each of 
these will have initialize/terminate method/free functions, and 
all of the objects they track that need to cleanup will have a 
terminate method. For example, I might have an aa in the graphics 
module that serves as a texture registry. And each texture will 
have a terminate method that calles into OpenGL to delete a 
texture.

=========
private Texture[string] _texRegistry;

class Texture
{
     private uint id;
     public void term()
     {
         glDeleteTextures(1, &id);
     }
}

void gfxTerm()
{
     if(!DerelictGL3.isLoaded) return;

     foreach(tex; _texRegistry.byValue)
         tex.term();
     clear(_texRegistry);
}
=========

The scope(exit) in the main method ensures that this termination 
chain is run every time the app exits regardless of the reason -- 
even when the Derelict libraries fail to load. So, if I'm going 
to be calling into the bound libraries in any of the termination 
functions, then at the top of the manager-level terminators I 
test to make sure the lib is loaded. If it isn't, I exit quick. 
Because loading the libraries is always the very first thing I 
do, if the libraries aren't loaded then there aren't going to be 
any resources to release.

For any short lived objects, I still don't rely on destructors 
but call the terminator manually. Perhaps it's my years of 
programming in C without ctors and dtors, but I find this process 
painless and just as easy as using a destructor.


More information about the Digitalmars-d-learn mailing list