Preventing shared_ptr from eating your singleton objects

Suppose you have a simple (non-threadsafe) singleton object like this:

class singleton
{
public:
   static singleton *getInstance()
   {
      if (instance == NULL)
      {
         instance = new singleton();
      }
      return instance;
   }

   void doStuff()
   {
      std::cout << "doing stuff" << std::endl;
   }

private:
   singleton()   {  }
   static singleton *instance;
};

singleton *singleton::instance = NULL;

Invoking this is easy:

singleton *s1 = singleton::getInstance();
s1->doStuff();

What happens if you decide to switch to boost::shared_ptr all over your app and convert your singleton pointer full of enthousiasm:

boost::shared_ptr<singleton> s1(singleton::getInstance());
s1->doStuff();

This will work until you reach the end of your scope, the shared_ptr will then call the destructor on your object! Wait a minute, that’s not what we want to happen here right!

The solution is actually quite simple. The singleton object here has a default public destructor (generated by the compiler). So we just add a private destructor like this:

class singleton2
{
public:
   static singleton2 *getInstance()
   {
      if (instance == NULL)
      {
         instance = new singleton2();
      }
      return instance;
   }

   void doStuff()
   {
      std::cout << "doing stuff2" << std::endl;
   }

private:
   singleton2()   {  }
   ~singleton2()  { // THIS WILL PREVENT USAGE OF SHARED_PTR!! }
   static singleton2 *instance;
};

singleton2 *singleton2::instance = NULL;

The cool thing is that this forces you to use a regular pointer (that will still work fine). If you try to use the class with the private destructor in combination with a shared_ptr the compiler will automatically complain:

shared_test.cpp: In function 'void boost::checked_delete(T*) [with T = singleton]':
/usr/include/boost/detail/shared_count.hpp:86:   instantiated from 'boost::detail::shared_count::shared_count(Y*) [with Y = singleton]'
/usr/include/boost/shared_ptr.hpp:149:   instantiated from 'boost::shared_ptr<T>::shared_ptr(Y*) [with Y = singleton, T = singleton]'
shared_test.cpp:108:   instantiated from here
shared_test.cpp:27: error: 'singleton::~singleton()' is private
/usr/include/boost/checked_delete.hpp:34: error: within this context

Cool stuff! It’s not pretty but at least it keeps your singletons safe…