Meyer’s Singleton - How to really write it up properly?Filed Under: Weekly Tuesday Dose of goodness
To all C++ people who have been working their guts out, you’ve probably heard of many singleton patterns. One of which is known as Meyer’s Singleton.
As we know, in C++, we should never depend on the order of initialization in order to expect certain things to work. This is the same for singletons especially when they’re static.
Therefore, this article explains how should singletons be implemented properly.
First of all, we need to understand the characteristics of a singleton.
1) It’s a single instance of an object type you define
2) It’s likely to be a static instance, value (stack) or pointer (heap)
3) Its constructors are either private or protected, callers have no access to instantiate the object by themselves
4) Destruction of a singleton is usually unpredictable. Even if you have a release method() which is not good enough.
What are the advantages of having a singleton?
1) Singular instance, good base for utility functions and variables that are too, singular.
2) Place a group or all the singular attributes or methods into a single C++ class, making it easier to manage
3) Need not instantiate, thus saving memory allocation time and becomes a helper which is single-liner and easy to maintain.
What are the disadvantages of having a singleton?
1) You can’t control what the ::getInstance() returns, therefore might have certain dangers. I’ll elaborate this later.
2) You cannot control the order of destruction of the singleton
3) You cannot explicitly destroy a singleton even with a release() method. Some might disagree, but let me explain why is it so later.
4) Function overcrowding can take place. This is more like an excuse, since functions should always be categorized accordingly to what they’re supposed to do and not just simply a dump into a single singleton class.
What is a definitely no-no for Singletons?
1) Having reference counting pointer attributes that depends on external resources like DLLs. This causes a drag in the release processes. For example, the DLL is most likely to be released before the singleton. Since it’s a reference counting pointer, the pointer held inside (by now a dangling pointer) will be deleted when it’s the singleton’s turn to die.
2) Having coupling to other singletons. That means, the state of your singleton depends on the state of another singleton. Doing this causes an undefined or inconsistent coupling which easily leads to stack overruns or heap corruption.
3) By right in normal circumstances without reference counting pointers, singletons should return as non-const reference to “behave” like an normal object while allowing users to modify the public attributes. Therefore, never assign this reference to a value. Otherwise you’re headed for trouble.
What are my recommendations?
I’ve always liked how C# handles singletons (aka Static objects) as compared to Java. Therefore I’ve added a macro to do this:
Singleton class: cStringTokenizer (for example)
#define StringTokenizer cStringTokenzier::getInstance( )
To use I don’t need to do this:
cStringTokenizer& tokenizer = cStringTokenizer::getInstance();
Instead, I can just simply do this:
StringTokenizer.tokenizeString(…. );
It’s elegant and doesn’t require the user to explicitly assign to a reference. Just like C# but the similar syntax in C++.
Regards,
Jeremy
- Permalink
- Admin
- 6 Mar 2009 11:23 AM
- Comments (0)