Singleton Design Pattern is used to restrict instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. Examples would include objects needed for logging, communication, database access, file manager, scheduler, etc. You could pass such an instance from method to method, or assign it to each object in the system. However, this adds a lot of unnecessary complexity. Simply put, singleton ensures that a class has only one instance, and provides a global point of access to it.
When to use:
- Global variables pass data between parts of the application, polluting the namespace. Also compilers doesn't guarantee the order in which they are instantiate and you may not have the complete information to instantiate at the time of instantiation, program startup.
- Several identical instances in different parts of the program represent the same thing, i.e. have identical copies of an object.
- Lazy initialization is desirable, i.e., every execution path of the application may not need the object, or it will be needed later in the process execution.
- When the object is completely responsible for managing its instances (can be multiple) and wants sole control over the number of instances of that particular class and their lifetimes.
Implementation:
Singleton classes itself are responsible for managing its sole instance. The sole instance is an ordinary object of its class, but that class is written so that only one instance can ever be created. This way, you guarantee that no other instance can be created. Furthermore, you provide a global point of access to that instance. The Singleton class hides the operation that creates the instance behind a static member function. This member function, traditionally called Instance(), returns a pointer to the sole instance. The class also declares a private static pointer to its instance, pInstance. When the static function Instance() is called for the first time, it creates the sole instance, assigns its address to pInstance, and returns that address. In every subsequent invocation, Instance() will merely return that address. In singleton class the constructor, assignment operator, and copy constructor are declared protected, to ensure that users couldn’t create local instances of the class.
Here's a declaration of such a class:
class Singleton
{
public:
static Singleton* Instance();
protected:
Singleton();
Singleton(const Singleton&);
Singleton& operator= (const Singleton&);
private:
static Singleton* pInstance;
};
{
public:
static Singleton* Instance();
protected:
Singleton();
Singleton(const Singleton&);
Singleton& operator= (const Singleton&);
private:
static Singleton* pInstance;
};
The class's implementation looks like this:
Singleton* Singleton::pInstance = 0;// initialize pointer
Singleton* Singleton::Instance ()
{
if (pInstance == 0) // is it the first call?
{
pInstance = new Singleton; // create sole instance
}
return pInstance; // address of sole instance
}
Singleton::Singleton()
{
//... perform necessary instance initializations
}
Singleton* Singleton::Instance ()
{
if (pInstance == 0) // is it the first call?
{
pInstance = new Singleton; // create sole instance
}
return pInstance; // address of sole instance
}
Singleton::Singleton()
{
//... perform necessary instance initializations
}
The singleton pattern must be carefully constructed in multi-threaded applications. If two threads are to execute the creation method at the same time when a singleton does not yet exist, they both must check for an instance of the singleton and then only one should create the new one. If the programming language has concurrent processing capabilities the method should be constructed to execute as a mutually exclusive operation.
Thread-safe Implementation:
Define two helper classes, mutex and mutex_locker:
class mutex
{
public:
mutex()
{
pthread_mutex_init(&m,0);
}
void lock()
{
pthread_mutex_lock(&m);
}
void unlock()
{
pthread_mutex_unlock(&m);
}
private:
pthread_mutex_t m;
};
{
public:
mutex()
{
pthread_mutex_init(&m,0);
}
void lock()
{
pthread_mutex_lock(&m);
}
void unlock()
{
pthread_mutex_unlock(&m);
}
private:
pthread_mutex_t m;
};
class mutex; // forward declaration
class mutex_locker
{
public:
mutex_locker(mutex &mx) // we are designed to be called under the RAII paradigm
{
pm = &mx;
pm->lock();
}
~mutex_locker()
{
pm->unlock();
}
private:
mutex *pm;
};
class mutex_locker
{
public:
mutex_locker(mutex &mx) // we are designed to be called under the RAII paradigm
{
pm = &mx;
pm->lock();
}
~mutex_locker()
{
pm->unlock();
}
private:
mutex *pm;
};
We then redefine the singleton class as follows:
class mutex; // forward declaration
class singleton
{
public:
static singleton* instance();
protected:
singleton();
private:
static singleton *inst;
static mutex m;
};
class singleton
{
public:
static singleton* instance();
protected:
singleton();
private:
static singleton *inst;
static mutex m;
};
Implementation of the singleton class:
singleton::singleton()
{
... // do whatever initialisation is necessary
}
singleton* singleton::instance()
{
if(inst == 0)
{
// Acquire mutex lock only if variable inst is still not initialized.
mutex_locker lock(m);
if(inst == 0) // Check again for null value, after acquiring the lock.
inst = new singleton;
}
return inst;
}
{
... // do whatever initialisation is necessary
}
singleton* singleton::instance()
{
if(inst == 0)
{
// Acquire mutex lock only if variable inst is still not initialized.
mutex_locker lock(m);
if(inst == 0) // Check again for null value, after acquiring the lock.
inst = new singleton;
}
return inst;
}
Runtime declaration of the static members:
singleton *singleton::inst = 0;
mutex singleton::m;
mutex singleton::m;
Issues:
- Singleton implementations do not allow convenient subclassing (static function can't be virtual in C++).
- Performance issues in multi-threaded environment, due to locking.