Design Pattern: The Singleton
Overview
Use the Singleton Design Pattern when you want to have only one instance of a class. This single instance must have a single global point of access. That is, regardless of where the object is hidden, everyone needs access to it.
The global point of access is the object's Instance() method.
Individual users need to be prevented from creating their own instances of the Singleton.
The Singleton represents a replacement for a global variable. Professional C++ developers avoid global variables for a variety of reasons.
Where many Singleton objects are required by an application, it may be necessary to construct a container of Singletons called a registry. Here individual Singleton objects can be stored with a key for retrieval.
A Singleton Class – Part 1
The SysParms class shown represents a class capable of being a Singleton. The default constructor is protected so only a derived class can execute it. This makes it possible to create an instance of the derived class but not an instance of the SysParms class itself.
Likewise the SysParms destructor is protected so it can be called only by a derived object. This will prevent just any user from deleting the Singleton. Of course, the destructor is virtual which allows the SysParms class to be used with polymorphism.
The Instance() method is static so you do not need a SysParms object to call it. In fact, it will be the Instance() method that you will use to create the SysParms object in the first place. This is called the lazy method of creating the object.
[code=cpp]
class SysParms
{
private:
SysParms(const SysParms&); //Prevents making a copy
protected:
SysParms(); //Only a SysParms member can call this
//Prevents a user from creating singleton objects
virtual ~SysParms(); //Prevents just anyone from deleting the singleton
public:
//The "official" access point.
static SysParms* Instance();
};
[/code]
The implementation of the SysParms class would be in a source file by itself.
Here you see the address of the single instance implemented as a variable inside an anonymous namespace. The reason for this is that the members of an anonymous namespace are in accessible outside the file where the namespace resides. That is, they have internal linkage.
The initial value of the address of the instance is set to 0. The SysParms singleton will not actually by created until it is required.
The static SysParms::Insta nce() method simply checks the address of the instance in the anonymous namespace and if the address is zero, the method creates a new SysParms object on the heap and stores the heap address in the namespace.
If the address in the anonymous namespace is not zero, it means the singleton has already been created. In this case, the Instance() methods just returns the address in the namespace.
[code=cpp]
//Use anonymous namespace to force internal linkage for instance
namespace
{
SysParms* instance = 0; //Address of the singleton
}
SysParms::SysPa rms()
{
}
SysParms::~SysP arms()
{
delete instance;
instance = 0;
}
//The "official" access point
SysParms* SysParms::Insta nce()
{
//"Lazy" initialization. Singleton not created until it's needed
if (!instance)
{
instance = new SysParms;
}
return instance;
}
[/code]
Using a Simple Singleton
To use the SysParms singleton, you need only call the Instance() method and you will receive the address of the singleton.
From there, you may execute whatever methods are on the singleton.
[code=cpp]
int main()
{
SysParms* theSysParmsSing leton;
cout << "Example A: Creating only one instance" << endl;
//
//SysParms obj; //ERROR: singleton objects cannot be created by the user
//
//Use Instance() method to locate singleton.
//Instance() is static as we have no object
theSysParmsSing leton = SysParms::Insta nce();
//
cout << "theSysParmsSin gleton is located at " << &theSysParmsSin gleton
<< endl;
return 0;
}
[/code]
A Singleton Class – Part 2
In this second part, the SysParms class is expanded and a derived class is added. Instances of the derived class, which are all singletons, are stored in a container, called a registry, with a retrieval key.
In this example, the singleton objects deal with sort sequences so there will be a singleton object for each of the sort sequences.
In this case, the sort sequences are either ascending or descending.
A Register() method has been added to store the singleton in the registry.
A Lookup() method has been added to retrieve singletons from the registry.
Lastly, there are accessor methods for changing or retrieving parameters from the singleton. For ease, the parameters are just a simple enum. In a real program the parameters would be returned as an object of a Parameter class.
Please note: Public virtual functions are discouraged because public virtual functions violate the concept of separation of interface from implementation. They are shown as public in this example for instructional purposes only.
[code=cpp]
class SysParms
{
private:
SysParms(const SysParms&); //Prevents making a copy
protected:
SysParms(); //Only a SysParms member or subclass can call this
virtual ~SysParms(); //Prevent just anyone from deleting the singleton
public:
enum Parms {ASCENDING, DESCENDING};
//The "official" access point.
static SysParms* Instance(const std::string& name);
//Register the singleton object by a name
//Returns false if registration failed
bool Register(const std::string& name, SysParms* obj);
//Returns 0 if name not in registry
SysParms* Lookup(const std::string& name);
//Parameter Interface:
//These should really be private.
virtual Parms GetParms()= 0;
virtual void SetParms(Parms in) = 0;
};
[/code]
The SysParms implementation file now expands to:
[code=cpp]
extern SingletonRegist ry theRegistry;
SysParms::SysPa rms()
{
}
SysParms::~SysP arms()
{
}
//The "official" access point
//
//You look up the singleton in theRegistry and return its address
//
SysParms* SysParms::Insta nce(const string& name)
{
return theRegistry.Loo kup(name);
}
bool SysParms::Regis ter(const string& name, SysParms* obj)
{
return theRegistry.Add (name, obj);
}
SysParms* SysParms::Looku p(const string& name)
{
return theRegistry.Loo kup(name);
}
[/code]
You can see the implementation of the Register() and Lookup() methods. The registry itself is in its own implementation file.
Here an STL map is used for the registry.
[code=cpp]
class SingletonRegist ry
{
private:
std::map<std::s tring, SysParms*> theRegistry;
public:
//Default ctor and dtor of std::map<> will be used
//Locate
SysParms* Lookup(const std::string& name);
//Add
bool Add(const std::string& name, SysParms* obj);
};
[/code]
The registry implementation is shown below.
A singleton is stored in the registry simply by creating a pair<> object with the supplied string as the retrieval key and a pointer to the singleton object. The pair is inserted in the map container.
A singleton is retrieved by accessing the map container using the string specified to retrieve the pair object from the map container. The second member of the pair is the address of the singleton corresponding to the supplied string. The method returns a null pointer if the singleton is not in the registry.
[code=cpp]
extern SingletonRegist ry theRegistry;
//Registry of Singletons.
SysParms* SingletonRegist ry::Lookup(cons t string& name)
{
pair<string, SysParms*> theEntry;
map<string, SysParms*>::ite rator itr = theRegistry.fin d(name);
if (itr == theRegistry.end ())
{
return 0; //not found
}
return itr->second;
}
bool SingletonRegist ry::Add(const string& name, SysParms* obj)
{
pair<string, SysParms*> theEntry;
theEntry.first = name;
theEntry.second = obj;
theRegistry.ins ert(theEntry);
return true;
}
[/code]
The singletons being put in the registry are:
[code=cpp]
class SortParms :public SysParms
{
private:
enum Parms seq;
public:
SortParms(const std::string& name);
~SortParms();
virtual Parms GetParms();
virtual void SetParms(Parms in);
};
[/code]
And are implemented as:
[code=cpp]
extern SingletonRegist ry theRegistry;
SortParms::Sort Parms(const std::string& name)
{
theRegistry.Add (name, this);
}
SortParms::~Sor tParms()
{
}
enum SysParms::Parms SortParms::GetP arms()
{
return this->seq;
}
void SortParms::SetP arms(Parms in)
{
this->seq = in;
}
[/code]
Notice these singletons register themselves when they are created by having the register code as part of the singleton constructor.
In a separate source file, the registry is created followed by the singletons. Again, the singleton objects are in an anonymous namespace which makes them inaccessible from anywhere. The only global point of reference not is the Lookup() method on the registry. Here is the implementation:
[code=cpp]
//The Registry object
SingletonRegist ry theRegistry;
//
//The SortParms objects
//
//The anonymous namespace makes them publicly inaccessible outside this file.
//
namespace
{
SortParms obj(std::string ("SortParms" )); //The singleton itself
SortParms obj1(std::strin g("SortParmsFor Person")); //The singleton itself
SortParms obj2(std::strin g("SortParmsFor Date")); //The singleton itself
}
[/code]
The above implementation is based on the feature that global variables are created in the order in which they are declared and that all global variables must be created before main() starts.
Based on that, you can see the registry is created followed by three singletons. These singletons register themselves using the string in the constructors.
Users must now call the Instance() method with one of those strings. The Instance() will use the string to look up the singleton in the registry and return a pointer to it.
[code=cpp]
int main()
{
SysParms* theSysParmsSing leton;
cout << "Example B: Creating a registered singleton" << endl;
//
//SysParms obj; //ERROR: singleton objects cannot be created by the user
//
//Use Instance() method to locate singleton.
theSysParmsSing leton = SysParms::Insta nce("SortParms" );
//
cout << "the SortParms Singleton is located at " << theSysParmsSing leton
<< endl;
theSysParmsSing leton = SysParms::Insta nce("SortParmsF orPerson");
//
cout << "the SortParmsForPer son Singleton is located at "
<< theSysParmsSing leton << endl;
theSysParmsSing leton = SysParms::Insta nce("SortParmsF orDate");
//
cout << "the SortParmsForDat e Singleton is located at "
<< theSysParmsSing leton << endl;
//Set a sort sequence for Person
SysParms::Insta nce("SortParmsF orPerson")->SetParms(SysPa rms::ASCENDING) ;
//Set a sort sequence for Date
SysParms::Insta nce("SortParmsF orDate")->SetParms(SysPa rms::DESCENDING );
//Retrieve sort sequence
enum SysParms::Parms rval = SysParms::Insta nce("SortParmsF orPerson")->GetParms();
if (rval == SysParms::ASCEN DING)
{
cout << "Sort Person Ascending" << endl;
}
else
{
cout << "Sort Person Descending" << endl;
}
//Retrieve sort sequence
rval = SysParms::Insta nce("SortParmsF orDate")->GetParms();
if (rval == SysParms::ASCEN DING)
{
cout << "Sort Date Ascending" << endl;
}
else
{
cout << "Sort Date Descending" << endl;
}
return 0;
}
[/code]
Using Handles
The examples in this article use pointers since pointer syntax is commonly understood. However, it is recommended that, in a real application, handles be used. You should refer to the article on Handles in the C/C++ Articles section.
Further Information
Refer to the book Design Patterns by Erich Fromm, et al, Addison-Wesley 1994.
This article shows only the conceptual basis of the Singleton pattern but not motivations and ramifications of using this pattern.
Copyright 2007 Buchmiller Technical Associates North Bend WA USA
Overview
Use the Singleton Design Pattern when you want to have only one instance of a class. This single instance must have a single global point of access. That is, regardless of where the object is hidden, everyone needs access to it.
The global point of access is the object's Instance() method.
Individual users need to be prevented from creating their own instances of the Singleton.
The Singleton represents a replacement for a global variable. Professional C++ developers avoid global variables for a variety of reasons.
Where many Singleton objects are required by an application, it may be necessary to construct a container of Singletons called a registry. Here individual Singleton objects can be stored with a key for retrieval.
A Singleton Class – Part 1
The SysParms class shown represents a class capable of being a Singleton. The default constructor is protected so only a derived class can execute it. This makes it possible to create an instance of the derived class but not an instance of the SysParms class itself.
Likewise the SysParms destructor is protected so it can be called only by a derived object. This will prevent just any user from deleting the Singleton. Of course, the destructor is virtual which allows the SysParms class to be used with polymorphism.
The Instance() method is static so you do not need a SysParms object to call it. In fact, it will be the Instance() method that you will use to create the SysParms object in the first place. This is called the lazy method of creating the object.
[code=cpp]
class SysParms
{
private:
SysParms(const SysParms&); //Prevents making a copy
protected:
SysParms(); //Only a SysParms member can call this
//Prevents a user from creating singleton objects
virtual ~SysParms(); //Prevents just anyone from deleting the singleton
public:
//The "official" access point.
static SysParms* Instance();
};
[/code]
The implementation of the SysParms class would be in a source file by itself.
Here you see the address of the single instance implemented as a variable inside an anonymous namespace. The reason for this is that the members of an anonymous namespace are in accessible outside the file where the namespace resides. That is, they have internal linkage.
The initial value of the address of the instance is set to 0. The SysParms singleton will not actually by created until it is required.
The static SysParms::Insta nce() method simply checks the address of the instance in the anonymous namespace and if the address is zero, the method creates a new SysParms object on the heap and stores the heap address in the namespace.
If the address in the anonymous namespace is not zero, it means the singleton has already been created. In this case, the Instance() methods just returns the address in the namespace.
[code=cpp]
//Use anonymous namespace to force internal linkage for instance
namespace
{
SysParms* instance = 0; //Address of the singleton
}
SysParms::SysPa rms()
{
}
SysParms::~SysP arms()
{
delete instance;
instance = 0;
}
//The "official" access point
SysParms* SysParms::Insta nce()
{
//"Lazy" initialization. Singleton not created until it's needed
if (!instance)
{
instance = new SysParms;
}
return instance;
}
[/code]
Using a Simple Singleton
To use the SysParms singleton, you need only call the Instance() method and you will receive the address of the singleton.
From there, you may execute whatever methods are on the singleton.
[code=cpp]
int main()
{
SysParms* theSysParmsSing leton;
cout << "Example A: Creating only one instance" << endl;
//
//SysParms obj; //ERROR: singleton objects cannot be created by the user
//
//Use Instance() method to locate singleton.
//Instance() is static as we have no object
theSysParmsSing leton = SysParms::Insta nce();
//
cout << "theSysParmsSin gleton is located at " << &theSysParmsSin gleton
<< endl;
return 0;
}
[/code]
A Singleton Class – Part 2
In this second part, the SysParms class is expanded and a derived class is added. Instances of the derived class, which are all singletons, are stored in a container, called a registry, with a retrieval key.
In this example, the singleton objects deal with sort sequences so there will be a singleton object for each of the sort sequences.
In this case, the sort sequences are either ascending or descending.
A Register() method has been added to store the singleton in the registry.
A Lookup() method has been added to retrieve singletons from the registry.
Lastly, there are accessor methods for changing or retrieving parameters from the singleton. For ease, the parameters are just a simple enum. In a real program the parameters would be returned as an object of a Parameter class.
Please note: Public virtual functions are discouraged because public virtual functions violate the concept of separation of interface from implementation. They are shown as public in this example for instructional purposes only.
[code=cpp]
class SysParms
{
private:
SysParms(const SysParms&); //Prevents making a copy
protected:
SysParms(); //Only a SysParms member or subclass can call this
virtual ~SysParms(); //Prevent just anyone from deleting the singleton
public:
enum Parms {ASCENDING, DESCENDING};
//The "official" access point.
static SysParms* Instance(const std::string& name);
//Register the singleton object by a name
//Returns false if registration failed
bool Register(const std::string& name, SysParms* obj);
//Returns 0 if name not in registry
SysParms* Lookup(const std::string& name);
//Parameter Interface:
//These should really be private.
virtual Parms GetParms()= 0;
virtual void SetParms(Parms in) = 0;
};
[/code]
The SysParms implementation file now expands to:
[code=cpp]
extern SingletonRegist ry theRegistry;
SysParms::SysPa rms()
{
}
SysParms::~SysP arms()
{
}
//The "official" access point
//
//You look up the singleton in theRegistry and return its address
//
SysParms* SysParms::Insta nce(const string& name)
{
return theRegistry.Loo kup(name);
}
bool SysParms::Regis ter(const string& name, SysParms* obj)
{
return theRegistry.Add (name, obj);
}
SysParms* SysParms::Looku p(const string& name)
{
return theRegistry.Loo kup(name);
}
[/code]
You can see the implementation of the Register() and Lookup() methods. The registry itself is in its own implementation file.
Here an STL map is used for the registry.
[code=cpp]
class SingletonRegist ry
{
private:
std::map<std::s tring, SysParms*> theRegistry;
public:
//Default ctor and dtor of std::map<> will be used
//Locate
SysParms* Lookup(const std::string& name);
//Add
bool Add(const std::string& name, SysParms* obj);
};
[/code]
The registry implementation is shown below.
A singleton is stored in the registry simply by creating a pair<> object with the supplied string as the retrieval key and a pointer to the singleton object. The pair is inserted in the map container.
A singleton is retrieved by accessing the map container using the string specified to retrieve the pair object from the map container. The second member of the pair is the address of the singleton corresponding to the supplied string. The method returns a null pointer if the singleton is not in the registry.
[code=cpp]
extern SingletonRegist ry theRegistry;
//Registry of Singletons.
SysParms* SingletonRegist ry::Lookup(cons t string& name)
{
pair<string, SysParms*> theEntry;
map<string, SysParms*>::ite rator itr = theRegistry.fin d(name);
if (itr == theRegistry.end ())
{
return 0; //not found
}
return itr->second;
}
bool SingletonRegist ry::Add(const string& name, SysParms* obj)
{
pair<string, SysParms*> theEntry;
theEntry.first = name;
theEntry.second = obj;
theRegistry.ins ert(theEntry);
return true;
}
[/code]
The singletons being put in the registry are:
[code=cpp]
class SortParms :public SysParms
{
private:
enum Parms seq;
public:
SortParms(const std::string& name);
~SortParms();
virtual Parms GetParms();
virtual void SetParms(Parms in);
};
[/code]
And are implemented as:
[code=cpp]
extern SingletonRegist ry theRegistry;
SortParms::Sort Parms(const std::string& name)
{
theRegistry.Add (name, this);
}
SortParms::~Sor tParms()
{
}
enum SysParms::Parms SortParms::GetP arms()
{
return this->seq;
}
void SortParms::SetP arms(Parms in)
{
this->seq = in;
}
[/code]
Notice these singletons register themselves when they are created by having the register code as part of the singleton constructor.
In a separate source file, the registry is created followed by the singletons. Again, the singleton objects are in an anonymous namespace which makes them inaccessible from anywhere. The only global point of reference not is the Lookup() method on the registry. Here is the implementation:
[code=cpp]
//The Registry object
SingletonRegist ry theRegistry;
//
//The SortParms objects
//
//The anonymous namespace makes them publicly inaccessible outside this file.
//
namespace
{
SortParms obj(std::string ("SortParms" )); //The singleton itself
SortParms obj1(std::strin g("SortParmsFor Person")); //The singleton itself
SortParms obj2(std::strin g("SortParmsFor Date")); //The singleton itself
}
[/code]
The above implementation is based on the feature that global variables are created in the order in which they are declared and that all global variables must be created before main() starts.
Based on that, you can see the registry is created followed by three singletons. These singletons register themselves using the string in the constructors.
Users must now call the Instance() method with one of those strings. The Instance() will use the string to look up the singleton in the registry and return a pointer to it.
[code=cpp]
int main()
{
SysParms* theSysParmsSing leton;
cout << "Example B: Creating a registered singleton" << endl;
//
//SysParms obj; //ERROR: singleton objects cannot be created by the user
//
//Use Instance() method to locate singleton.
theSysParmsSing leton = SysParms::Insta nce("SortParms" );
//
cout << "the SortParms Singleton is located at " << theSysParmsSing leton
<< endl;
theSysParmsSing leton = SysParms::Insta nce("SortParmsF orPerson");
//
cout << "the SortParmsForPer son Singleton is located at "
<< theSysParmsSing leton << endl;
theSysParmsSing leton = SysParms::Insta nce("SortParmsF orDate");
//
cout << "the SortParmsForDat e Singleton is located at "
<< theSysParmsSing leton << endl;
//Set a sort sequence for Person
SysParms::Insta nce("SortParmsF orPerson")->SetParms(SysPa rms::ASCENDING) ;
//Set a sort sequence for Date
SysParms::Insta nce("SortParmsF orDate")->SetParms(SysPa rms::DESCENDING );
//Retrieve sort sequence
enum SysParms::Parms rval = SysParms::Insta nce("SortParmsF orPerson")->GetParms();
if (rval == SysParms::ASCEN DING)
{
cout << "Sort Person Ascending" << endl;
}
else
{
cout << "Sort Person Descending" << endl;
}
//Retrieve sort sequence
rval = SysParms::Insta nce("SortParmsF orDate")->GetParms();
if (rval == SysParms::ASCEN DING)
{
cout << "Sort Date Ascending" << endl;
}
else
{
cout << "Sort Date Descending" << endl;
}
return 0;
}
[/code]
Using Handles
The examples in this article use pointers since pointer syntax is commonly understood. However, it is recommended that, in a real application, handles be used. You should refer to the article on Handles in the C/C++ Articles section.
Further Information
Refer to the book Design Patterns by Erich Fromm, et al, Addison-Wesley 1994.
This article shows only the conceptual basis of the Singleton pattern but not motivations and ramifications of using this pattern.
Copyright 2007 Buchmiller Technical Associates North Bend WA USA
Comment