I was working on my engine the other day (I’m working on an engine called denj, by the way) and I was getting ready to start a graphics module. My first task was to separate the opengl context creation code from the window creation code as much as I could (SDL requires the SDL_WINDOW_OPENGL flag to be passed to windows upon creation if you want to use OpenGL but that’s not so bad). So I started a new Renderer class that was going to hold the context and do render-y things. I moved the context creation code from the Window class, tidied a few things up and added declared a new renderer in my graphics test function (pretty much main wrapped in a try-catch). It built. Awesome. Then I go to run it aaaaand… seg fault. What?
After some messing around and inserting logs into semi-random bits of code, I discovered that it was happening on an opengl function call. Not just any function call, but the first function call. Obviously, it was some kind of problem with opengl. On a hunch, I added some log calls into the constructor of my new renderer class in case for some weird reason it wasn’t being called or was failing or something. It was fine. Then I added a log call in the destructor of my new renderer class and found my problem. My renderer and the context it managed were being destructed immediately after being constructed.
As it turns out, D’s GC is a lot fluffier in terms of behaviour than what I expected. I expected that if you created a class, it would stay active until end of scope. Which is what D’s structs do, but apparently D’s classes are different. If you have a single reference to a class and never use it, the GC will pick up on that and remove it. In a regular every day program this mightn’t be as much an issue, but my Renderer class was interfacing with a C library, OpenGL. OpenGL, being a C library, isn’t aware of the GC nor is the GC aware of the global state contained in OpenGL. Therefore, my using of the global state managed by my renderer was ignored as use of my renderer.
So I knew what the problem was, so what was my solution? Gross.
Obviously this is super temporary but it fixed the problem enough that I could begin working on the actual API of my renderer. I could probably remove the reference as of last night considering that I’m actually using the class for rendering things in my main loop now. But I’d still like to find some way to keep it alive just incase I want to use raw opengl at some point. Although, my API is already nicer to use (not that hard) so that probably won’t happen soon.
Closing thought. If you plan on using a garbage collected language, make sure you read up on what the hell the garbage collector actually does and when it does it. Otherwise you’ll have weird bugs for (seemingly) no reason.