In Search of a Perfect Singleton


"Design and programming are human activities; forget that and all is lost." - Bjarne Stroustrup
CodeGuru Note: The code in this article is not thread safe. If it were, this perhaps would be an article about the perfect singleton.

Singleton Pattern

To begin with, a 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.

A 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 you need singletons? You use them:

  • To coordinate actions across the system
  • To improve upon the efficiency of the system

Care should be taken to identify the need and benefits of using a singleton. Often, one tends 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. But, let me just do a quick recap.

The rule of thumb for singletons is that the direct instantiation through the constructor should be prevented. How do you 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 that the default access in a C++ class is private. But, in the case of Java, the constructor inherits the access modifier of the class. If no access modifier is defined on the class, 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 the 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 you have prevented the direct instantiation of the class, you need to provide a mechanism to access the object. Here is how to do this.

C++
class Singleton {
public:
   static Singleton* getInstance() {
      if (NULL == _instance) {
         _instance = new Singleton();
      }
      return _instance;
   }

private:
   // default constructor
   Singleton() {
   }

   // the single instance of the object
   static Singleton* _instance;
};

Singleton* Singleton::_instance = NULL;
Java
public class Singleton {
   public static Singleton getInstance() {
      if (null == _instance) {
         _instance = new Singleton();
      }
      return _instance;
   }

   // default constructor
   private Singleton() {
   }

   // the single instance of the object
   private static Singleton _instance;
};

You have ensured that only one instance exists and was given access to the same. Now, other required functionality can be added to the singleton class.

Is That All?

Are you done? No, not exactly. Remember I had said that this is an attempt to create a perfect singleton. So, what is wrong with the above? Have I missed something? Yes, I did. Although I 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

You need to declare these also as private to prevent access. You may ask why. You do so because:

  • A copy constructor will create a new object from the existing one. But, you are interested in limiting the instance to only one.
  • An assignment operator is not required for a Singleton; "_instance" is the only data member and 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:
   // default constructor
   Singleton() {
   }

   // copy constructor
   Singleton(const Singleton&) {
   }

   // assignment operator
   Singleton& operator=(const Singleton&)

{
      return *this;
   }

   // the single instance of the object
   static Singleton* _instance;
};
 
Singleton* Singleton::_instance = NULL;

In the case of Java, you tend to forget about cloning just as you forget about copying the constructor. Although your singleton class does not define a clone method, you need to do so because the java.lang.Object class from which your singleton is inherited from defines the clone() method. To make your Singleton foolproof, you need to add a clone() method and prevent access to the same. Because you cannot make it private, you either can make it protected or override it and throw an exception or both.

Java
public class Singleton {
   public static Singleton getInstance() {
      if (null == _instance) {
         _instance = new Singleton();
      }
      return _instance;
   }

   // default constructor
   private Singleton() {
   }

   // clone
   protected Object clone() throws

CloneNotSupportedException {
      throw new CloneNotSupportedException();
   }

   // the single instance of the object private
   static Singleton _instance;
};

In Search of a Perfect Singleton

How to Release the Singleton

You have prevented alternates from creating another instance of the class. But, what about the destruction of the instance? Can you define a destructor and delete _instance in it? Although this looks very simple enough, it isn't. If you do the above, you will have you code as the following:

C++
class Singleton {
public:
. . .
. . .
   ~Singleton() {
      delete _instance;
   }
};

What actually happens in that destructor is that delete _instance invokes the destructor again and 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 you have done. Hence, I recommend that you 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:
   // default constructor
   Singleton() {
   }

   // default destructor
   ~Singleton() {
   }

   // copy constructor
   Singleton(const Singleton&) {
   }

   // assignment operator
   Singleton& operator=(const Singleton&)

{
      return *this;
   }

   // the single instance of the object
   static Singleton* _instance;
};

Singleton* Singleton::_instance = NULL;

Tune the Singleton's Release

Now, that looks perfect. All said and; 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 you do? You will use a reference count to ensure that the actual destruction of the singleton happens only when it is not being referenced anymore. So, you 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:
   // default constructor
   Singleton() {
   }

   // default destructor
   ~Singleton() {
   }

   // copy constructor
   Singleton(const Singleton&) {
   }

   // assignment operator
   Singleton& operator=(const Singleton&)

{
      return *this;
   }

   // the single instance of the object
   static Singleton* _instance;

   // the count of references
   static int _referenceCount;
};

int Singleton::_referenceCount  = 0;
Singleton* Singleton::_instance = NULL;

This is much better, but it is still not completely foolproof. If the releaseInstance() is called more than what's 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 releaseInstance() is not called by a user, the singleton will never be deleted and you are back to depending on the post program termination cleanup.

In the case of Java, as far as my knowledge goes, garbage collection takes care of releasing the instance when it is not referenced anymore. So, ther is not much of a problem as was envisaged above for C++.

Conclusion

A simple way to handle the limitations in C++ is through effective code review. But, the risk still remains because it is directly proportionate to the effectiveness of the code review. Although there is other 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 code was written using Eclipse 3.2 with CDT.


About the Author

Aravindan Premkumar

The Saint is a software professional having worked extensively on UI development on VC++ in the intial years. He currently works as a System Analyst catering to project development & management. He loves to explore & improve his all round knowledge & technical skills. He is addicted to playing computer games, loves to travel, listen to music & watch movies.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds