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.

Reply via email to