Reputation: 481
I'm writing a resource manager which is able to allocate unique IDs(for example for OpenGL uniform buffer binding points so you don't need to keep track of the used ones), so if there would be more instances of the manager this would be a problem because each should know which IDs are already used. So one way is to use a Singleton:
class ResourceManager
{
private:
HandleAllocator uniform_binding_points;
...
public:
static ResourceManager& Get()
{
static ResourceManager resource_manager;
return resource_manager;
}
unsigned int AllocateUniformBindingPoint()
{ ... }
...
private:
ResourceManager()
{ }
~ResourceManager()
{ }
}
Or to use static members, so there can be more instances, but each instance is using the same state:
class ResourceManager
{
private:
static HandleAllocator uniform_binding_points;
...
public:
unsigned int AllocateUniformBindingPoint()
{ ... }
...
}
So my question is what's the difference and if there's a better solution(considering testability too)? I know many people are hating singletons but in my opinion the only difference is that you need to receive the Singleton instance with Get() which is one method call more, but you can store a reference so you are calling Get() once. Also i've read this: http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/ and i need to say that with composition and aggregation you can achieve the exact same "dependency hiding", so don't use those too?...
Upvotes: 3
Views: 565
Reputation: 2767
I think this is a style issue, so there's no definite answer. However, I will give some reasons why I think singleton is the better solution here.
The Get
method (I usually calls it instance
) clearly state that this is a singleton (at least for anyone who read your document and your document said it's a singleton). You may have multiple references initialized as
auto &mgr = ResourceManager::Get();
But they are all the same. It makes it clear that any function calls on the these instances are calls on the same object. And thus usual guidelines can be more easily followed. For example, if the application is multi-threading aware, then we are aware that usually one should not call mutable methods simultaneously on the same object (provided that the implementation of ResourceManager
follow such guidelines). Now consider the static member approach,
ResourceManager mgr1;
ResourceManager mgr2;
If I am a user and not aware of how it is implemented, I don't see any harm in calling two mutable methods on each of these two objects, which is not true. In short, you can consider Singleton a little bit more "self-documented", at least for users who understand what Singleton is.
In addition, the non-copyable property of singletons also make some unintended use of easier to be detected at compile time.
Last but not least, singleton give you more flexibility in managing longevity. In your example, a Meyer's singleton is used and thus no big difference. But if the need arise, you can change the implementation of singleton to fine tune its longevity
Upvotes: 3