Sunday, August 09, 2009

Implementing a Well behaved Singleton - 4

In part-3 of this series, I talked about implementing singleton such that construction sequence is guaranteed and the destruction is guaranteed however the sequence in which the destruction happens is not guaranteed.

Sometimes one singleton object depends on another singleton object. In such cases, the technique described in part-3 will be useful to ensure that the singleton's are constructed in the correct order. However, since it uses the 'function static objects' , the destruction sequence is compiler dependent. Suppose Singleton object Foo depends on singleton object Bar, this technique will ensure correct order of construction. However, compiler may call the destructors of Foo and Bar in the wrong order, since compiler is not aware of this dependency.

To fix the destruction sequence we will take the help of little known function called 'atexit'. You can find the details of 'atexit' here. or in the compiler help. The important property is If more than one atexit function has been specified by different calls to this function, they are all executed in reverse order as a stack, i.e. the last function specified is the first to be executed at exit. This is property we need to ensure that the singltons are destructed in the 'reverser order' of their construction.

class FooSingleton
static FooSingleton& GetSingleton(void);

private :
static void DestroySingleton(void);

private :
static FooSingleton* m_pFoo;
int m_var;

// In the .cpp file
FooSingleton::m_pFoo = NULL;

// Code construct foo singleton
::atexit(FooSingleton::DestroySingleton); // THIS IS KEY }

if( m_pFoo == NULL)
m_pFoo = new FooSingleton;

delete m_pFoo;

Now if FooSingleton and BarSingleton objects are coded in similar way and FooSingleton depends on BarSingleton then 'FooSingleton::GetSingleton' will call BarSingleton::GetSingleton(). Hence the BarSingleton will get constructed first and in the process the BarSingleton::DestroySingleton function will get registered with 'atexit. Next FooSingleton::DestroySingleton will get registered with 'atexit'.

When program exits, the functions registered with 'atexit' will be called in the reverse order of registration. Hence the FooSingleton::DestroySingleton will get called first and then BarSingleton::DestroySingleton.

Now we have ensured that the singleton objects are destructed in the reverse order of their construction sequence. This technique is completely 'standards compliant' and hence should work on all C++ compilers.

Many developers have misconception that Singleton is the easiest design pattern to implement. As you can see implementing a 'well behaved' singleton is NOT such an easy problem to solve.


Vinay Marje said...

I guess in class definition GetFooObj() & DestroyFoo() should be GetSingleton() & DestroySingleton()

Vinay Marje said...

... and GetSingleton() should return a pointer.

Nitin Bhide said...

Class definition is corrected.

Also GetSingleton should return a 'reference'. I have corrected it to return (*m_pFoo). The idea is to avoid accidental deletion of 'pointer'. Returning a 'reference' is an indication to the class user that he/she should not delete/destroy the returned object.