How to wrap SDL?

Stanislav Blinov blinov at loniir.ru
Mon Jan 24 07:02:29 PST 2011


22.01.2011 23:04, Sean Eskapp пишет:
> I'm using the Derelict SDL bindings, and I'm wrapping some parts of SDL in my
> own objects. Originally, I was using classes, but this caused a number of
> errors when the program exited, since Derelict unloaded itself before the
> garbage collector took care of destructing my classes.
>
> So I switched to scope classes. This works fine, but I've been told they're
> being removed from the language (?) and to use structs instead for RAII.
>
> How should I be wrapping this SDL stuff?
>
Sorry for not mentioning this earlier on Derelict forum (that was you, 
right?), I remember I intended to write this but I think I got 
distracted and forgot about it. You can go the other way around:

Since the initial problem with segfaults occurs because the order of 
calling dtors for your objects and dtor for derelict.sdl.sdl is 
indeterminable, you may want to somewhat 'determine' it:

1. Create a module, say, sdlresource.d.
2. In this module, import derelict.sdl.sdl. (see below why).
3. In this module, create a base class for all your SDL wrappers.
4. This base class' (default) ctor should store a 'this' reference in 
some (module-private) storage such as array/AA.
5. This base class' dtor should remove 'this' reference from that storage.
6. Create a static dtor for sdlresource.d, which would iterate the 
storage and delete/clear() all references that are still left at that point.

That's it. You now can use dtors of subclasses to customize SDL resource 
deallocation. Such approach guarantees that DerelictSDL will not be 
unloaded before all your resources are freed (because sdlresource.d 
imports derelict.sdl.sdl). The only caveat that's left is calling that 
dtor. For now, you can still use 'delete', but you'll have to switch to 
clear() later, when it's finished and 'delete' is finally deprecated. 
But that's easily localized by creating something like this:

void safeDelete(T)(T p) if (is(T == class) || is(pointerTarget!(T) == 
struct)) // pointerTarget is in std.traits
{
     delete p; // switch to clear() later
}

With this approach, either the GC will deallocate resources, or forced 
deallocation in sdlresource.d's static destructor will occur.
I agree, this is a hacky method, but it should work well. The 'storage' 
may be a simple array. In this case, for the sake of efficiency, 
resources may be indexed and simple unstable removal (backswapping and 
removing last element) may be used.

PS. The other 'caveat' that actually messes not only this approach, but 
the whole Derelict usage, is that in Derelict modules, loader objects 
(such as DerelictSDL) and static dtors are not shared. (This is actually 
a result of unfinished introduction for handling TLS by default in D2). 
That means that in a multithreaded program, as soon as one of the 
threads finishes, Derelict bindings will be invalidated for the whole 
application. That's nasty, I should probably mention that to aldacron or 
even come up with the fix.

I hope this helps.


More information about the Digitalmars-d-learn mailing list