So, as I'm sure many seasoned veterans of know, the initialization order of static variables is undefined by the C++ standard. While this generally isn't a problem, it can quickly become a problem if you're doing something like overriding the memory manager, as is the case in most games. Any structure that wants to call out to a custom allocator, must wait for the allocator to be initialized. One way around this is to have the allocator as a self-instantiating singleton, but what if you're doing something more complicated?
An example is a self-registration system. This is a fairly common occurrence: you have a factory class that takes care of instantiating other classes based on something data-driven. In my scenario, this is a component system, but it really could be anything. Each component needs to register itself with the factory class so the factory can proceed to instantiate them. You have two options here: one is to have a giant init method that looks something like this:
void InitFactory() { Factory.RegisterComponent(ComponentA); Factory.RegisterComponent(ComponentB); Factory.RegisterComponent(ComponentC); Factory.RegisterComponent(ComponentD); Factory.RegisterComponent(ComponentE); // and so on... }
The problem with this is that it requires you #include every component header, and remember to register every component manually. Not my idea of fun.
The second is to use an auto registration system. Basically, you create an auto-registration template class:
template <class Component> class ComponentAutoRegister { public: ComponentAutoRegister(); }; template <class Component> ComponentAutoRegister<Component>::ComponentAutoRegister() { Factory::Instance()->RegisterComponent(...); }
And then add that to any component class:
class MyComponent { static ComponentAutoRegister<MyComponent> __AutoRegistration; };
When the static auto-registration template class is constructed, it will automatically register your class with the factory.
The problem is this: If your factory class has any other dependencies, it will need to initialize those first. If this usually happens post-main, or as part of any other variable being statically initialized, you can't use this auto-registration system. Damn.
Here's my scenario: I have a table of fixed strings that needs to be initialized with a table page size and an allocator before it can be used. My component factory uses fixed strings as keys for each component. Instead of attempting to make a long chain of singletons which would only end up coupling all the systems together (something I wanted to avoid) I slightly edited my auto-registration system to auto-register a callback instead, which is then called post initialization:
template <class Component> class ComponentAutoRegister { public: ComponentAutoRegister(); static void PerformAutoRegister(); }; template <class Component> void ComponentAutoRegister<Component>::PerformAutoRegister() { Factory::Instance()->RegisterComponent(...); } template <class Component> ComponentAutoRegister<Component>::ComponentAutoRegister() { Application::AddPostInitHook(&PerformAutoRegister); }
The callbacks are held in an opaque linked list, managed by a zero-overhead pool pulled out of system memory. It could actually be held in an array as well, but being able to free the memory once post-initialization is complete makes me happy.
And this could easily be extended to support multiple layers of auto-registered post-initialization, so long as the layers are kept free of dependencies. For now, I only need the one layer, so I'll keep it simple.
This may seem hacky, but it does work pretty well. What are your thoughts?