The client calls the accessor function (using the class name and scope resolution operator) whenever a reference to the single instance is required.
Singleton should be considered only if all three of the following criteria are satisfied:
The Singleton pattern can be extended to support access to an application-specific number of instances.
The "static member function accessor" approach will not support subclassing of the Singleton class. If subclassing is desired, refer to the discussion in the book.
Deleting a Singleton class/instance is a non-trivial design problem. See "To kill a Singleton" by John Vlissides (C++ Report, Jun 96, pp10-19) for a discussion.
static
attribute in the "single
instance" class.
static
accessor function in the class.
protected
or
private
.
Before | After | |
---|---|---|
// A global variable is default initialized - // when it is declared - but it is not ini- // tialized in earnest until its first use. // This requires that the initialization // code be replicated throughout the appli- // cation. class GlobalClass { int m_value; public: GlobalClass( int v=0 ) { m_value = v; } int get_value() { return m_value; } void set_value( int v ) { m_value = v; } }; // Default initialization GlobalClass* global_ptr = 0; void foo( void ) { // Initialization on first use if ( ! global_ptr ) global_ptr = new GlobalClass; global_ptr->set_value( 1 ); cout << "foo: global_ptr is " << global_ptr->get_value() << '\n'; } void bar( void ) { if ( ! global_ptr ) global_ptr = new GlobalClass; global_ptr->set_value( 2 ); cout << "bar: global_ptr is " << global_ptr->get_value() << '\n'; } int main( void ) { if ( ! global_ptr ) global_ptr = new GlobalClass; cout << "main: global_ptr is " << global_ptr->get_value() << '\n'; foo(); bar(); } // main: global_ptr is 0 // foo: global_ptr is 1 // bar: global_ptr is 2 | // Make the class responsible for its own // global pointer and "initialization on // first use" (by using a private static // pointer and a public static accessor // method). The client uses only the public // accessor method. class GlobalClass { int m_value; static GlobalClass* s_instance; GlobalClass( int v=0 ) { m_value = v; } public: int get_value() { return m_value; } void set_value( int v ) { m_value = v; } static GlobalClass* instance() { if ( ! s_instance ) s_instance = new GlobalClass; return s_instance; } }; // Allocating and initializing GlobalClass's // static data member. The pointer is being // allocated - not the object inself. GlobalClass* GlobalClass::s_instance = 0; void foo( void ) { GlobalClass::instance()->set_value( 1 ); cout << "foo: global_ptr is " << GlobalClass::instance()->get_value() << '\n'; } void bar( void ) { GlobalClass::instance()->set_value( 2 ); cout << "bar: global_ptr is " << GlobalClass::instance()->get_value() << '\n'; } int main( void ) { cout << "main: global_ptr is " << GlobalClass::instance()->get_value() << '\n'; foo(); bar(); } // main: global_ptr is 0 // foo: global_ptr is 1 // bar: global_ptr is 2 |
Facade objects are often Singletons because only one Facade object is required. [GoF, p193]
State objects are often Singletons. [GoF, p313]
It's relatively easy to protect Singleton against multiple instantiations because there is good language support in this area. The most complicated problem is managing a Singleton's lifetime, especially its destruction ... There are serious threading issues surrounding the pattern. [Alexandrescu, p155] For C++ lifetime issues, see Alexandrescu, pp133-145. For C++ multi-threaded implementation, see Alexandrescu, pp145-148. For Java multi-threaded implementation, see Freeman, pp179-182. For subclassing the Singleton instance, see Gamma, pp130-131.
The advantage of Singleton over global variables is that you are absolutely sure of the number of instances when you use Singleton, and, you can change your mind and manage any number of instances. [Ralph Johnson]
The Singleton design pattern is one of the most inappropriately used patterns. Singletons are intended to be used when a class must have exactly one instance, no more, no less ... [Designers] frequently use Singletons in a misguided attempt to replace global variables ... A Singleton is, for intents and purposes, a global variable. The Singleton does not do away with the global; it merely renames it. [Hyslop, p51]
When is Singleton unnecessary? Short answer: most of the time. Long answer: when it's simpler to pass an object resource as a reference to the objects that need it, rather than letting objects access the resource globally ... The real problem with Singletons is that they give you such a good excuse not to think carefully about the appropriate visibility of an object. Finding the right balance of exposure and protection for an object is critical for maintaining flexibility. [Kerievsky, pp115-116]
Our group had a bad habit of using global data, so I did a study group on Singleton. The next thing I know Singletons appeared everywhere and none of the problems related to global data went away. The answer to the global data question is not, "Make it a Singleton." The answer is, "Why in the hell are you using global data?" Changing the name doesn't change the problem. In fact, it may make it worse because it gives you the opportunity to say, "Well I'm not doing that, I'm doing this” – even though this and that are the same thing. [Frieder Knauss]