MIRA
|
The singleton pattern is a software design pattern that restricts the instantiation of a class to one single object - the singleton. It is useful when exactly one object of a certain class is needed and needs to be accessed globally, or where only one instance is allowed.
Singletons can be and should be used instead of global variables, since their initialization can be controlled better. Moreover, the singleton implementation ensures that there really exists only one instance. (When using global or static variables with Windows DLLs, there exists an instance of a global/static variable per DLL!)
The Singleton template class provides a very generic implementation of the singleton pattern.
There are two different ways to create a singleton for your class.
The preferred way is to subclass your class from the Singleton template class as follows:
Please note that you have to specify the type of your class as first parameter of the Singleton template class.
The second way to use the Singleton allows you to use your class as both: a singleton, and a "normal" class that can be used to create several objects:
In both cases you can access your singleton by calling the instance() method:
Please note, that this kind of usage is not allowed for the explicit singleton (see below).
The Singleton can be freely configured using policies that control the instantiation, creation and lifetime. The policies are specified as additional template parameters.
The instantiation policy controls WHEN the singleton object is created. Currently, there are three different policies.
The LazyInstantiation policy is the default policy. It ensures that the singleton object will be instantiated only at the moment when the instance() method is called for the first time. If the instance() method is never called, the singleton will never be instantiated:
For convenience, LazySingleton is provided to create singletons with lazy instantiation:
The EagerInstantiation policy ensures early/eager instantiation, i.e. the singleton object will be instantiated BEFORE the first line of the applications main() function is executed. This is useful if the singleton must do some initialization as early as possible. Please note that the singleton will not be instantiated if the instance() method is never called!
For convenience, EagerSingleton is provided to create singletons with eager instantiation:
The ExplicitInstantiation policy allows full control of the construction and destruction time of the singleton. The singleton must be instantiated (and hence destroyed) explicitly by the user. It will throw XLogical, if someone tries to create a second instance of the singleton, or if someone tries to use the singleton instance when it was not yet created. Due to the explicit instantiation, this singleton type is the only singleton that allows to pass parameters to the constructor.
For convenience, ExplicitSingleton is provided to create singletons with explicit instantiation:
The creation policy controls the way HOW singleton object is created. Currently, there are three different policies.
The CreateUsingNew policy uses the new/delete operators for creating/destructing the singleton object.
The CreateStatic policy creates the singleton object in static memory, i.e. without allocating memory. Instead, the memory is provided by the compiler at compile time.
The CreateUsing<...>::Allocator policy creates the singleton object using a custom allocator. The allocator must be specified as template parameter as follows:
The lifetime policy controls how singleton object is destructed. Currently, there are two different policies.
The NormalLifetime policy implements the normal C++ lifetime, i.e. singletons that are created first, are destroyed last.
The NoDestroyLifetime policy never destroys the singleton object, i.e. the singleton's destructor will never be called. However, the occupied memory will be freed when the process terminates.
The lock policy controls the thread-safety when constructing the singleton. Currently, there are two different policies.
The MutexLock policy ensures thread-safety when the singleton is instantiated, i.e. if two concurrent threads simultaneously access a singleton, that was not yet created.
The NoLock policy does not ensure any thread-safety. If two concurrent threads simultaneously access a singleton, that was not yet created, this may result in a multiple instantiation of the singleton class. However, if you can ensure, that a singleton is used by a single thread only or if at least the first instantiation of the singleton is guaranteed to be non-concurrent, you can use this policy, as it does not introduce any additional overhead.