Game Engine, C 1, P 13, Managed Singleton pattern
My next pattern to discuss is the "Managed singleton" pattern. It is very similar to the ordinary singleton pattern, but it has a few key differences. The ordinary singleton pattern works in C++ by storing the instance of the class in an internal static instance variable, for example inside a
get_instance()
function. This works well. Moreover, due to inner-workings of static variables inside functions, its lifetime is: created before first access, destroyed before shutdown. But what if I want more control over the lifetime? I can't get it in an ordinary way. And here is when managed singleton comes into play.Managed singleton idea
The idea behind this pattern is, that I should be able to create and destroy the singleton variable whenever I want. In my implementation, I get the value from the singleton class by using
get()
and ptr()
. Having such a class allows me to store global variables without strong binds to implementation details. In the future, I'll improve this pattern by allowing users to store external pointers inside the singleton. This should help with inheritance.Implementation
My implementation of this pattern can be boiled down to a few functions, that I'll show right here.
namespace vul {
namespace patterns {
template<class _Ty, template <class> class _Alloc = std::allocator >
class managed_singleton
{
public:
using value_type = _Ty;
using allocator_type = _Alloc<_Ty>;
private:
using _Alty_traits = std::allocator_traits<allocator_type>;
static _Ty* _value;
allocator_type _allocator;
bool _init;
public:
managed_singleton()
: _allocator(), _init(false)
{ }
managed_singleton(const allocator_type& al)
: _allocator(al), _init(false)
{ }
template<class ...Args>
int init(Args... args)
{
if (_init) return 0;
_value = _Alty_traits::allocate(_allocator, 1);
if (_value == nullptr) return 0;
_Alty_traits::construct(_allocator, _value, std::forward<Args>(args)...);
_init = true;
return 1;
}
int term()
{
if (!_init) return 0;
_Alty_traits::destroy(_allocator, _value);
_Alty_traits::deallocate(_allocator, _value, 1);
_value = nullptr;
_init = false;
return 1;
}
static _Ty& get() { return *_value; }
static _Ty* ptr() { return _value; }
};}}
template <class _Ty, template <class> class _Alloc>
_Ty* vul::patterns::managed_singleton<_Ty, _Alloc>::_value = nullptr;
As you can see, it relies on the partial template specification of the value pointer at the bottom. With this, I can store a single instance of the value for each template parameter, that is given. All in all, this pattern can be used to hold global game engine systems, that can be later accessed through it or other aliases.
The corresponding commit is here. Next I'll talk about IoC Containers.
Comments
Post a Comment