Design Considerations
The constructor is responsible for all the initialization operations of the Singleton object. For example, if we're creating a Singleton print spooler, it will create an empty job queue, check the status of all the currently active printers, etc. Because the constructor is protected, a client that tries to instantiate Singleton object directly will get a compilation error. Note that this constructor will get called on the first call to Instance().
Storing a pointer rather than an actual object has two advantages. First, it enables Singleton to use lazy instantiation. Secondly, it supports polymorphism -- you may assign the pointer to a subclass of Singleton.
The Design Patterns literature elegantly ignores the issue of a Singleton's destructor. This isn't a trivial issue, as it may seem at first. Remember that if you intend to derive classes from Singleton, you must declare its destructor virtual. Alternatively, you may forgo destructors both in the base class and its descendants. However, if you do define a destructor, don't be tempted to use it to destroy the Singleton object. The problem is that calling:
delete _instance;
will invoke the destructor, which in turn will try to delete _instance once more, infinitely. That said, don't ignore the fact that Instance() allocates an object on the free-store, and that that object must be deleted explicitly to avoid a memory leak. The simplest solution is to delete _instance at the end of the program:
int main()
{
Singleton *p = Singleton::Instance();
//..use p
delete p;
}
This is however, a violation of basic OOD principles. Imagine what would happen if another thread calls Instance() one again. A better solution is to define another static member function that explicitly destroys the Singleton object and resets _instance:
void Singleton::Destroy()
{
delete _instance;
_instance=0;
}
This way, a subsequent call to Instance() will work as expected, because it checks whether _instance is 0 before returning. Another solution that is suitable for single-threaded environments is to use a local static object:
//using a static Singleton object
//not suitable for multithreaded apps
Singleton* Singleton::Instance ()
{
static Singleton s;
return &s; // _instance isn't needed in this case
}