“Design and programming are human activities; forget that and all is lost.” - Bjarne Stroustrup
Singleton Pattern
Well, to begin with, Singleton is one of the most commonly used - as well as misused - design patterns. Why did I say misused? You will get the answer as you read on.
Singleton Pattern is usually used to restrict the instances of a class, that is the objects within the life cycle of the software program to one. But why do we need to use Singletons? We use them:
- to coordinate actions across the system
- to improve upon the efficiency of the system
Care should be taken to identify the need & benefits of using a singleton. Often, we tend to use singletons to hide a global object.
How to Create a Singleton?
Most of us know how to create a singleton. We have done it so many times by now, isn't it? But let us just do a quick recap.
The thumb rule for singletons is that the direct instantiation through the constructor should be prevented. Then how do we instantiate or access the object? The solution is to provide a method that creates a new instance of the object if one does not exist. If an instance already exists, it simply returns a reference to that object.
C++
class Singleton {
Singleton() {
}
};
Remember the default access in a C++ class is private
. But in case of Java, constructor inherits the access modifier of the class. If no access modifier is defined on the class, then the default constructor has the default access implied by no access modifier. (Reference: Java Language Specification Second Edition 8.8.7 Default Constructor).
This means that in case of Java, care should be taken to explicitly make the access modifier of the constructor as private
.
Java
package ...;
public class Singleton {
private Singleton() {
}
};
Now that we have prevented the direct instantiation of the class, we need to provide a mechanism to access the object. Here is how we do this:
C++
class Singleton {
public:
static Singleton* getInstance() {
if (NULL == _instance) {
_instance = new Singleton();
}
return _instance;
}
private:
Singleton() {
}
static Singleton* _instance;
};
Singleton* Singleton::_instance = NULL;
Java
public class Singleton {
public static Singleton getInstance() {
if (null == _instance) {
_instance = new Singleton();
}
return _instance;
}
private Singleton() {
}
private static Singleton _instance;
};
Now we have ensured that only one instance exists and gives access to the same. Now other required functionality can be added to the Singleton class.
Is That All?
Are we done? No, not quite exactly. Remember I had said that this is an attempt to create a perfect Singleton. So what is wrong with the above? Have we missed something? Yes, we did. Though we have prevented the direct instantiation, an object can still be created. If you recollect the basics, all C++ classes, apart from having their default constructors also have:
- copy constructor
- assignment operator
We need to declare these also as private
so as to prevent the access. You may ask why. We do so because:
- a copy constructor will create a new object from the existing one. But we are interested in limiting the instance to only one.
- an assignment operator is not required for a Singleton; ‘_instance’ is the only data member & has to point to the same object across all instances.
C++
class Singleton {
public:
static Singleton* getInstance() {
if (NULL == _instance) {
_instance = new Singleton();
}
return _instance;
}
private:
Singleton() {
}
Singleton(const Singleton&) {
}
Singleton& operator=(const Singleton&) {
return *this;
}
static Singleton* _instance;
};
Singleton* Singleton::_instance = NULL;
In case of Java, we tend to forget about cloning just as we forget about copy constructor. Though our Singleton class does not define a clone method, we need to do so because java.lang.Object
class from which our Singleton is inherited from defines the clone()
method. So to make our Singleton foolproof, we need to add clone()
method & prevent access to the same. Since we cannot make it private
, we can either make it protected
or override it & throw an exception or both.
Java
public class Singleton {
public static Singleton getInstance() {
if (null == _instance) {
_instance = new Singleton();
}
return _instance;
}
private Singleton() {
}
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
static Singleton _instance;
};
How Do We Release the Singleton?
Now we have prevented alternatives to create another instance of the class. But what about the destruction of the instance? Can we define a destructor & delete _instance
in it? This though looks very simple enough, it isn’t. If you do the above, you will have your code as:
C++
class Singleton {
public:
. . .
. . .
~Singleton() {
delete _instance;
}
};
What actually happens in that destructor, is that delete _instance
invokes the destructor again & puts it into an infinite loop. So the easy way out seems to be to depend on the post program termination clean-up to release the memory. But then it is not a good practice to depend on the post program termination clean up for the new that we had done. Hence I recommend to have a releaseInstance()
and to prevent access to the default destructor by making it private
.
C++
class Singleton {
public:
static Singleton* getInstance() {
if (NULL == _instance) {
_instance = new Singleton();
}
return _instance;
}
static void releaseInstance() {
if (NULL != _instance) {
delete _instance;
_instance = NULL;
}
}
private:
Singleton() {
}
~Singleton() {
}
Singleton(const Singleton&) {
}
Singleton& operator=(const Singleton&) {
return *this;
}
static Singleton* _instance;
};
Singleton* Singleton::_instance = NULL;
Tune the Release of Singleton
Now that looks perfect. All said & done, there still is a catch. When should releaseInstance()
be called? Ideally, this should be called when the application exits. But in a real time situation when there are multiple developers working on the application code, it just remains a mirage. So what do we do? We will use a reference count to ensure that the actual destruction of the Singleton happens only when it is not being referenced anymore. So we add a static
reference count to the Singleton.
C++
class Singleton {
public:
static Singleton* getInstance() {
if (NULL == _instance) {
_instance = new Singleton();
}
_referenceCount++;
return _instance;
}
static void releaseInstance() {
_referenceCount--;
if ((0 == _referenceCount) && (NULL != _instance)) {
delete _instance;
_instance = NULL;
}
}
private:
Singleton() {
}
~Singleton() {
}
Singleton(const Singleton&) {
}
Singleton& operator=(const Singleton&) {
return *this;
}
static Singleton* _instance;
static int _referenceCount;
};
int Singleton::_referenceCount = 0;
Singleton* Singleton::_instance = NULL;
This is much better, but still not completely foolproof. If the releaseInstance()
is called more than required by one particular user, it will lead to a situation where an instance is deleted even though it is actually still very much in use. On the contrary, if the releaseInstance()
is not called by a user, then the Singleton will never be deleted & we are back to depending on the post program termination clean up.
In case of Java, as far as my knowledge goes, garbage collection takes care of releasing the instance when it is not referenced anymore. So not much problem as envisaged above for C++.
Finale
A simple way to handle the limitations in C++ is through effective code review. But the risk still remains as it is directly proportionate to the effectiveness of the code review. Though there is another workaround to minimize this risk, there always seems to be a way to hack through.
I am working on a way to perfect the implementation of this common pattern.
Note
The above holds good only for single-threaded applications. I will updated the article for multi-threaded applications shortly. The code was written using Eclipse 3.2 with CDT.
History
- 14th September, 2006: Initial post