Creating Singleton Objects using Visual C++

Object creation is an important step in any Object Oriented Application. An application can use the services of a class only after creating an object of it. In most applications, creating an object of a class is very straight forward, that is, by declaring the instance of the class. For example, to create an object MyObj of class MyClass, the C++ syntax is MyClass MyObj;. But, in a complex Object Oriented Application, the task of creating the objects is usually assigned to other classes. The book, Design Patterns : Elements of Reusable Object-Oriented Software by Erich Gamma et al. ( Addison-Wesley, 1995 ) explores different approaches that can be used for object creation under the classification, Creational Patterns.

This article discusses a Creational Pattern called Singleton and explains different approaches for implementing Singleton pattern using a Visual C++ example.

What is a Singleton Class?

Sometimes, you may want to have only one object for a given class and this object should be easily accessible. For example, an Application should have only one Application object and the Job schedulers should share a single Job Queue object. A global variable may provide easy access, but using a global variable will not stop the user from creating more than one object and moreover it is discouraged in Object Oriented Programming. In the above example, the Application class should not allow the user to create more than one object of it and the Job Queue class should ensure that a single Job Queue object is shared by all the Job schedulers. Application and Job Queue classes are called Singleton classes. So, what is a Singleton class ? A class that assures a maximum of ONE object of its type at a given time and provides a global access point to this object is a Singleton class.

An Example

This article uses "Message Handlers" as an example to explain the concept of a Singleton class. An application interacts with the user through messages. This includes errors, warnings and information messages. The application can use a single message handler object to format or log these messages before presenting it to the user. Hence, the message handler class can be a Singleton class.

The approaches that are presented in this article includes

Singletons using static variables

Listing 1 contains a simple message handler class. The constructor and destructor are declared as protected members to avoid direct object creation or destruction. The static method GetMsgHndlr returns a pointer to the static member m_MsgHndlr.

Listing 1a shows a variation of message handler class, and it uses a function static member instead of a class static member. The object is created only when GetMsgHndlr is called for the first time.

Advantage

  1. Ensures only one message handler object is present all the time and eliminates the need for a global variable.
  2. Message handler using function static member ( Listing 1a ) creates the object, only when GetMsgHndlr is called for the first time. So the object is created only if it is needed.

Disadvantage

    Class of the object CMsgHndlr is hard coded and the application cannot use a different message handler, without changing the class.

Singletons on heap

Listing 2 contains a message handler class that creates object on the heap. A key is passed as a parameter to GetMsgHndlr for creating the required message handler object. Now, the message handler class not only ensures the uniqueness of the message handler object, but it is also responsible for creating the required message handler object. An object is created when GetMsgHndlr is called for the first time and the subsequent call returns the created object.

Advantage

    Applications can select the required message handler by passing the appropriate key. Only message handler class needs to be changed to include a new message handler.

Disadvantage

  1. CMsgHndlr class should be aware of all its subclasses and include their header files, to create their objects.
  2. CMsgHndlr class is responsible for creating message handler objects based on the key passed to GetMsgHndlr method and this needs to be changed when a new message handler is added.
  3. Application is forced to choose the required message handler class at link time.

Singletons using RTTI

Run-time type information ( RTTI ) is a mechanism to determine the type of an object during program execution. RTTI is now available as part of C++ language. This approach uses MFCs CRuntimeClass to identify the class of object dynamically and create it when needed ( Listing 3 ).

CObject, the root class of MFC provides the support for Run-time class information and dynamic object creation. To use these services, CMsgHndlr class should be inherited from CObject, DECLARE_DYNCREATE( CMsgHndlr ) macro must be included in the header file and IMPLEMENT_DYNCREATE( CMsgHndlr, CObject ) macro must be added to the implementation file.

GetMsgHndlr method takes CRuntimeClass * as parameter. It ensures that the given Runtime class is of type CMsgHndlr and returns the created object. RUNTIME_CLASS( class_name ) macro can be used to get CRuntimeClass information for a given C++ class.

Advantage

    GetMsgHndlr can create object of CMsgHndlr or its descendants just with their Runtime class information, without having to know their exact class names. This method need not change when a new message handler subclass is created.

Disadvantage

    Choice of the message handler class is made at link time. If a new message handler class needs to be used, the application must pass the appropriate run time class information to GetMsgHndlr.

Self-Registering Singletons

Lets take an example of an application making the choice of message handler at runtime based on a key value set in the Registry or value passed as a Command Line Argument. Since, the selection of message handler is made at runtime, the application should be aware of all the available message handlers to select the appropriate one based on the runtime parameter, using a series of if statements. ( Listing 4 )

Listing 4 shows that, the code which checks and creates the message handler is moved from CMsgHndlr ( Listing 2 ) to SelectMsgHndlr function in the application ( Listing 4 ). This kind of function should be written in all the applications using message handler. To complicate the situation further, let us assume that the message handlers are contained in a shared library or a DLL and the application is not aware of all available message handlers ( new message handler classes may be added in future to the library ). How can we select the right message handler ? It is simple. Each message handler class should register their runtime class information in a Message Handler Registry. This runtime information is used to create the required message handler object when needed. I have extended the idea of "Self-Registering, Objects in C++" by Jim Beveridge ( Dr. Dobbs Journal, August 1998 ), to register the runtime class information. ( Listing 5 )

CObjRegistry maintains a registry object, in which the runtime class information is stored. CMsgHndlrRegistry is a template class inherited from CObjRegistry. Message handler classes register their runtime class information to CObjRegistry via CMsgHndlrRegistry. GetMsgHndlr method takes a key as a parameter, gets the required runtime class information from CObjRegistry and creates the required message handler object.

Advantage

  1. The class information of the message handlers are registered only at runtime, so a new message handler class can be added without affecting other pieces of the code.
  2. Choice of the message handler class can be made at run time. If a new message handler class needs to be used, it can be specified to the application through Registry or as a Command Line Argument, without changing the application.

Whos going to Bell the Cat ?

Object cleanup is a problem with Singleton. Message handler object is created on the heap by GetMsgHndlr method, but whos going to delete it ? Strictly speaking, the application or the client module should delete the object after its use. It will result in a memory leak, if the object is not deleted. So, I feel that CMsgHndlr should be smart enough to take care of its own cleanup.

Smart Singletons

Listing 6 contains smart message handler that takes care of its cleanup. CMsgHndlr class employs a Smart Cleaner ( CSmartCleaner ) to do the cleanup job. It declares a static data member of CSmartCleaner class and says "Hello" to CSmartCleaner through SetObject( this ) during construction and says "Goodbye" through SetObject( NULL ) during destruction. When an application terminates, C++ will not do an automatic cleanup of the objects allocated on heap, but cleans up the static objects. So, the static CSmartCleaner object gets destructed at the end of application and the destructor of CSmartCleaner deletes the message handler object, if the application forgets to delete it.

Benefits of Singleton

  1. Singleton ensures that only one object of the class type is created and provides a global access to this object.
  2. Singleton classes can be used to create an object of its derived class, and the applications can choose the required singleton object without much change in the code.
  3. Singleton eliminates the need for a global variable.

Beyond Singleton

Even though Singleton is the main topic of discussion, this article introduces the following techniques to C++ developers.

  1. An approach to use MFCs RTTI support for dynamic object creation.
  2. An approach for self-registering objects.
  3. An approach for object cleanup ( smart cleaner ), that can be used by a class to make sure that its instances are cleaned up properly.
  4. An approach that can be extended to create more than one object of a class in a controlled fashion.

Conclusion

Singleton classes are used in well-known applications. MFCs CWinApp is a good example, it ensures that an application has only object of CWinApp type. Smalltalks metaclass is another example for a singleton class. A metaclass is the class of a class and there is only one instance of a metaclass for providing class level services.

This article used a message handler example to introduce the concept of Singletons. It walked through the different ways of implementing Singletons with their advantages and disadvantages. It started with a simple approach for creating Singletons using static variables, then it explained how an object of a Singleton class ( or its sub class ) could be created on heap. It also showed how the other two approaches - Singletons using RTTI and Self Registering Singletons, can be implemented using Visual C++ RTTI support. These two approaches can also be implemented using any other C++ compiler that has RTTI support. Smart Singletons presented an idea for object cleanup and showed how it can take care of its own cleanup.

Acknowledgments

Special thanks to my friend Sree Meenakshi for her helpful suggestions in improving the clarity and presentation of this article.

Listing 1 - Message Handler using static variables

class CMsgHndlr
{
	public :
		static CMsgHndlr * GetMsgHndlr();
	protected :
		CMsgHndlr(){}
		virtual ~CMsgHndlr(){}
		static CMsgHndlr m_MsgHndlr;	// Static instance of Message handler class.
};

CMsgHndlr  CMsgHndlr::m_MsgHndlr;
CMsgHndlr * CMsgHndlr::GetMsgHndlr()		
{
	return & m_MsgHndlr;
}

Listing 1a - Variation of GetMsgHndlr using Function static members instead of class static

CMsgHndlr * CMsgHndlr::GetMsgHndlr()		
{
	static CMsgHndlr MsgHndlr;	// Create object, when called for the first time
	return & MsgHndlr;
}

Listing 2 - Message Handler on heap

class CMsgHndlr
{
	public :
		static CMsgHndlr * GetMsgHndlr( LPCSTR );
		virtual ~CMsgHndlr(){}
	protected :
		CMsgHndlr(){}
		static CMsgHndlr * m_pMsgHndlr;		
};

CMsgHndlr * CMsgHndlr::m_pMsgHndlr = NULL;
CMsgHndlr * CMsgHndlr::GetMsgHndlr( LPCSTR lpszKey )		
{
	if(m_pMsgHndlr  == NULL ) 
	{
		if( stricmp( lpszKey, "MSGHNDLR" ) == 0 ) 
		{
			m_pMsgHndlr = new CMsgHndlr;
		}
		else if( stricmp( lpszKey, "SMPHNDLR" ) == 0 ) 
		{
			m_pMsgHndlr = new CSmpHndlr;
		}
	}
	return m_pMsgHndlr;
}

Listing 3 - Message Handler using RTTI

class CMsgHndlr : public CObject
{
	public :
		static CMsgHndlr * GetMsgHndlr( CRuntimeClass * );
		DECLARE_DYNCREATE( CMsgHndlr )
		virtual ~CMsgHndlr(){}
	protected :
		CMsgHndlr(){}
		static CMsgHndlr * m_pMsgHndlr;		
};

IMPLEMENT_DYNCREATE( CMsgHndlr, CObject )
CMsgHndlr * CMsgHndlr::m_pMsgHndlr = NULL;
CMsgHndlr * CMsgHndlr::GetMsgHndlr( CRuntimeClass * pRuntimeClass )
{
	ASSERT( pRuntimeClass != NULL );
	if( m_pMsgHndlr != NULL ) 
	{
		return m_pMsgHndlr;
	}
	CRuntimeClass * pBaseClass = RUNTIME_CLASS( CMsgHndlr );
	if(pRuntimeClass ->IsDerivedFrom( pBaseClass ) == FALSE )
	{
		return NULL;
	}
	m_pMsgHndlr = ( CMsgHndlr * ) pMsgHndlrClass->CreateObject();
	return m_pMsgHndlr;
}

Listing 4 -Selecting message handler using the key

CMsgHndlr * SelectMsgHndlr( LPCSTR lpszKey )
{
	if( stricmp(lpszKey, "MSGHNDLR" ) == 0 )
	{
		return CMsgHndlr::GetMsgHndlr( RUNTIME_CLASS( CMsgHndlr ) );
	}
	else if( stricmp( lpszKey, "SMPHNDLR" ) == 0 )
	{
		return CMsgHndlr::GetMsgHndlr( RUNTIME_CLASS( CSmpHndlr ) );
	}
	return NULL;
}

Listing 5 - Self-Registering Singletons

// Object Registry class to store Runtime class information
class CObjRegistry 
{
	public :
		CObjRegistry( CRuntimeClass * pRuntimeClass, LPCSTR lpszKey )
		{
			ASSERT( pRuntimeClass != NULL );
			ASSERT( lpszKey != NULL );
			GetRegistry().SetAt( lpszKey, pRuntimeClass );
		}
	        static BOOL GetRuntimeClass( LPCSTR lpszKey, CRuntimeClass * & rpRuntimeClass )
		{
			return GetRegistry().Lookup( lpszKey, ( LPVOID & ) rpRuntimeClass );
		}
	private :
		static CMapStringToPtr & GetRegistry()
		{
			static CMapStringToPtr	Registry;
			return Registry;
		}
};

// Message handler registry class, to which Message handlers get registered
template <class T> class CMsgHndlrRegistry : public CObjRegistry
{
	public :
		CMsgHndlrRegistry( CRuntimeClass * pRuntimeClass, LPCSTR lpszKey ) : 
		CObjRegistry( pRuntimeClass, lpszKey ) {	}
};

// Message handler registration and GetMsgHndlr method in CMsgHndlr
static CMsgHndlrRegistry< CMsgHndlr > gMsgHndlr( RUNTIME_CLASS( CMsgHndlr ), 
	"MSGHNDLR" );
CMsgHndlr * CMsgHndlr::GetMsgHndlr( LPCSTR lpszKey )
{
	CRuntimeClass * pRuntimeClass = NULL;
	if( CObjRegistry::GetRuntimeClass( lpszKey, pRuntimeClass ) == FALSE )
	{
		return NULL;
	}
	// Call GetMsgHndlr in listing 3 with runtime class information
	return GetMsgHndlr( pRuntimeClass );
}

// Message handler registration code in CSmpHndlr
static CMsgHndlrRegistry< CSmpHndlr > gSmpHndlr( RUNTIME_CLASS( CSmpHndlr ), 
	"SMPHNDLR" );
// Application code to select the message handler
CMsgHndlr * SelectMsgHndlr( LPCSTR lpszKey )
{
	return CMsgHndlr::GetMsgHndlr( lpszKey );
}

Listing 6 - Smart Singletons

class CMsgHndlr : public CObject
{
	protected :
		CMsgHndlr()
		{
			m_SmartCleaner.SetObject( this ); 
		}
		static CMsgHndlr 	* m_pMsgHndlr;
	public :
		static CMsgHndlr 	* GetMsgHndlr( CRuntimeClass * );
		virtual ~CMsgHndlr()
		{
			m_SmartCleaner.SetObject( NULL );
			CMsgHndlr::m_pMsgHndlr = NULL;
		}
	private :
		static CSmartCleaner	m_SmartCleaner;
};

class CSmartCleaner
{
	public :
		CSmartCleaner( CObject * pObject = NULL ) : m_pObject( pObject ) { }
		virtual ~CSmartCleaner() 
		{
			if( m_pObject != NULL )
			{
				delete m_pObject;
			}
		}
		void SetObject( CObject * pObject )
		{
			m_pObject = pObject;
		}
		CObject * GetObject()
		{
			return m_pObject;
		}
	private :
		CObject * m_pObject;
};

Download demo project - 59 KB



Comments

  • New to the world of singletons

    Posted by Legacy on 12/22/2001 12:00am

    Originally posted by: Athelston Green

    Please could anyone help me with the concept of singletons.
    I think I understand about the concept of only creating one object from a class, but what is confusing me is how do I create the singleton object in my main program when the class constructor is protected. There is a function to access this protected function, but how can I call this when the object has not been created.

    This my be a simple problem but I have been struggling with this problem for weeks.

    Many thanks
    Athelston

    Reply
  • New to the world of singletons

    Posted by Legacy on 12/22/2001 12:00am

    Originally posted by: Athelston Green

    Please could anyone help me with the concept of singletons.
    I think I understand about the concept of only creating one object from a class, but what is confusing me is how do I create the singleton object in my main program when the class constructor is protected. There is a function to access this protected function, but how can I call this when the object has not been created.

    This my be a simple problem but I have been struggling with this problem for weeks.

    Many thanks
    Athelston

    Reply
  • Question on the Singleton article code listing

    Posted by Legacy on 04/06/2000 12:00am

    Originally posted by: Manish Y.

    class CMsgHndlr
    
    {
    public :
    static CMsgHndlr * GetMsgHndlr();

    protected :
    CMsgHndlr(){}
    virtual ~CMsgHndlr(){}
    static CMsgHndlr m_MsgHndlr;
    static int m_intMember;
    static double m_dblMember;
    };

    CMsgHndlr CMsgHndlr::m_MsgHndlr;
    CMsgHndlr * CMsgHndlr::GetMsgHndlr()
    {
    return & m_MsgHndlr;
    }

    This code from Listing 1 does not compile on my machine,
    If I make the destructor public, it compiles.
    or if I remove the external definition of the static member "m_MsgHndlr", it does.

    am i missing anything?
    Also, can anyone enlighten as to what scenario would warrant the use of a static member of a type same as the declaring class.

    Thanks in advance for any answers.

    Reply
  • A thought on safety of singelton classes

    Posted by Legacy on 10/06/1999 12:00am

    Originally posted by: Tomaz Stih

    Using static variables (Listing 1) for singleton or anywhere else in class or at global scope is not safe. If you use it from another singleton class at program startup (in ctor) what assures you that it will be properly initialized when you are trying to use it?

    This problem is fixed by putting static variable in function (the way you did it in Listing 2 and Listing 5 for Registry) or putting it on heap and JIT creation.

    Tomaz

    Reply
  • re: unable to hide the listbox of the combo box

    Posted by Legacy on 05/17/1999 12:00am

    Originally posted by: Vijayakumar Balakrishnan

    Call m_CoolCombo.ShowDropDown(FALSE) from the OnPaint method of the dialog, as well as the
    OnDropDownCoolCombo() method.
    
    

    Regards, Vijay

    Reply
  • RAS is for networking; TAPI is for telephony

    Posted by Legacy on 05/04/1999 12:00am

    Originally posted by: Phil Hord

    To simply dial a voice (or other) number, use TAPI services, not RAS.

    Check out the TAPI examples on MSDN.

    Reply
  • Pattern Hatching

    Posted by Legacy on 04/23/1999 12:00am

    Originally posted by: Ferdi Smit

    There's a 'follow-up' on Design Patterns called:
    
    

    "Pattern Hatching, Design Patterns Applied" - John Vlissides

    It contains a 12 page discussion called 'to kill a singleton' where various strategies are discussed to destruct the singleton at program exit (eg. with auto pointers) Some attention is also given to thread safety.

    Reply
  • Singleton Deletion

    Posted by Legacy on 01/05/1999 12:00am

    Originally posted by: Paul Whitehead

    When it comes to singletons call me a simpleton if you will but it seems to me that not many people are clear about the singleton cleanup. This is shown, for example, by previous comments on this page re: delete and not to delete the static member pointer (taking the Design Patterns example).

    If I may quote from the webpage: "When an application terminates, C++ will not do an automatic cleanup of the objects allocated on heap, but cleans up the static objects."

    Can this be true? Does the "cleanup of static objects" include freeing of any new'ed memory? If not, how does the singleton example given in "Design Patterns" not leak when there is no explicit deletion going on? Or does it leak? I ask the question as NuMega's Bounds Checker (v5.0) insists I have a leak and Microsoft's Visual C++ 5.0 (+ the ubiquitous Service Pack 3) doesn't report any leaks.

    I've looked through the ARM and can't see much re: deletion of new'ed memory with static / global pointers. Does anyone _really_ know what happens to that new'ed memory pointed to by a static class member when the program exits? If so, please enlighten me and keep my New Year going well...

    P.S. yes, the quirky email address really is my corporate email address!

    Reply
  • Brilliant

    Posted by Legacy on 11/15/1998 12:00am

    Originally posted by: Shimon Crown

    A masterful article. I shall certainly be using some of the tricks you describe in my future code.

    One comment is that use of Self-Registering singletons is similar to COMs Running Object Table (ROT).
    Singleton COM executables are ensured by registering to the ROT when running. When the user attempts to
    run a second instance of the application use of the ROT just hands it back the already existing object.

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

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds