473,597 Members | 2,156 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Design Patterns: The Singleton

weaknessforcats
9,208 Recognized Expert Moderator Expert
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.

Expand|Select|Wrap|Line Numbers
  1.  
  2. class SysParms
  3. {     
  4.    private:
  5.         SysParms(const SysParms&);  //Prevents making a copy
  6.  
  7.    protected:
  8.         SysParms();       //Only a SysParms member can call this
  9.                      //Prevents a user from creating singleton objects
  10.         virtual ~SysParms();  //Prevents just anyone from deleting the singleton
  11.  
  12.    public:
  13.  
  14.  
  15.        //The "official" access point.
  16.        static SysParms* Instance();
  17.  
  18. };
  19.  
  20.  
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.

Expand|Select|Wrap|Line Numbers
  1.  
  2. //Use anonymous namespace to force internal linkage for instance
  3.  
  4. namespace
  5. {
  6.     SysParms* instance = 0;        //Address of the singleton
  7.  
  8. }
  9.  
  10. SysParms::SysParms()
  11. {
  12.  
  13. }
  14. SysParms::~SysParms()
  15. {
  16.     delete instance;
  17.                 instance = 0;
  18. }
  19.  
  20. //The "official" access point
  21. SysParms* SysParms::Instance()
  22. {
  23.    //"Lazy" initialization. Singleton not created until it's needed
  24.    if (!instance)
  25.    {
  26.       instance = new SysParms;
  27.    }
  28.    return instance;
  29. }
  30.  
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.

Expand|Select|Wrap|Line Numbers
  1. int main()
  2. {
  3.    SysParms* theSysParmsSingleton;
  4.    cout << "Example A: Creating only one instance" << endl;
  5.  
  6.    //
  7.    //SysParms obj;  //ERROR: singleton objects cannot be created by the user
  8.    //
  9.    //Use Instance() method to locate singleton. 
  10.    //Instance() is static as we have no object
  11.    theSysParmsSingleton = SysParms::Instance();
  12.    //
  13.    cout << "theSysParmsSingleton is located at " << &theSysParmsSingleton 
  14.           << endl;
  15.  
  16.  
  17.  
  18.  
  19.    return 0;
  20. }
  21.  
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.

Expand|Select|Wrap|Line Numbers
  1. class SysParms
  2.     private:
  3.          SysParms(const SysParms&);  //Prevents making a copy
  4.  
  5.     protected:
  6.          SysParms();       //Only a SysParms member or subclass can call this
  7.          virtual ~SysParms(); //Prevent just anyone from deleting the singleton
  8.  
  9.     public:
  10.        enum Parms {ASCENDING, DESCENDING};
  11.  
  12.  
  13.  
  14.     //The "official" access point. 
  15.     static SysParms* Instance(const std::string& name);
  16.  
  17.     //Register the singleton object by a name
  18.     //Returns false if registration failed
  19.     bool Register(const std::string& name, SysParms* obj);
  20.  
  21.     //Returns 0 if name not in registry
  22.     SysParms* Lookup(const std::string& name);
  23.  
  24.    //Parameter Interface:
  25.    //These should really be private. 
  26.    virtual Parms GetParms()= 0; 
  27.    virtual void SetParms(Parms in) = 0;
  28.  
  29. }; 
  30.  
The SysParms implementation file now expands to:

Expand|Select|Wrap|Line Numbers
  1. extern SingletonRegistry theRegistry;
  2.  
  3.  
  4. SysParms::SysParms()
  5. {
  6.  
  7. }
  8. SysParms::~SysParms()
  9. {
  10.  
  11. }
  12.  
  13. //The "official" access point
  14. //
  15. //You look up the singleton in theRegistry and return its address
  16. //
  17. SysParms* SysParms::Instance(const string& name)
  18. {
  19.  
  20.     return theRegistry.Lookup(name);
  21.  
  22. }
  23.  
  24. bool SysParms::Register(const string& name, SysParms* obj)
  25. {
  26.     return theRegistry.Add(name, obj);
  27. }
  28.  
  29. SysParms* SysParms::Lookup(const string& name)
  30. {
  31.     return theRegistry.Lookup(name);
  32. }
  33.  
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.

Expand|Select|Wrap|Line Numbers
  1. class SingletonRegistry
  2. {
  3.    private:
  4.     std::map<std::string, SysParms*> theRegistry;        
  5.  
  6.    public:
  7.     //Default ctor and dtor of std::map<> will be used
  8.  
  9.     //Locate 
  10.     SysParms*   Lookup(const std::string& name);        
  11.  
  12.     //Add
  13.     bool Add(const std::string& name, SysParms* obj);
  14. };
  15.  
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.

Expand|Select|Wrap|Line Numbers
  1. extern SingletonRegistry theRegistry;
  2.  
  3. //Registry of Singletons.
  4.  
  5. SysParms* SingletonRegistry::Lookup(const string& name)
  6. {
  7.     pair<string, SysParms*> theEntry;
  8.     map<string, SysParms*>::iterator itr = theRegistry.find(name);
  9.     if (itr == theRegistry.end())
  10.     {
  11.         return 0;  //not found
  12.     }
  13.     return itr->second;    
  14. }
  15.  
  16. bool SingletonRegistry::Add(const string& name, SysParms* obj)
  17. {
  18.     pair<string, SysParms*> theEntry;
  19.     theEntry.first = name;
  20.     theEntry.second = obj;
  21.  
  22.     theRegistry.insert(theEntry);
  23.  
  24.     return true;  
  25.  
  26. }
  27.  
The singletons being put in the registry are:
Expand|Select|Wrap|Line Numbers
  1. class SortParms :public SysParms
  2. {
  3.  
  4.    private:
  5.      enum  Parms seq;
  6.  
  7.  
  8.    public:
  9.     SortParms(const std::string& name);
  10.     ~SortParms();
  11.     virtual Parms GetParms(); 
  12.     virtual void SetParms(Parms in);
  13. };
  14.  
And are implemented as:

Expand|Select|Wrap|Line Numbers
  1. extern SingletonRegistry theRegistry;
  2.  
  3. SortParms::SortParms(const std::string& name)
  4. {
  5.     theRegistry.Add(name, this);
  6. }
  7. SortParms::~SortParms()
  8. {
  9.  
  10. }
  11.  
  12.  
  13.  
  14. enum SysParms::Parms SortParms::GetParms()
  15. {
  16.     return this->seq;
  17.  
  18. }
  19. void SortParms::SetParms(Parms in)
  20. {
  21.         this->seq = in;
  22. }
  23.  
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:

Expand|Select|Wrap|Line Numbers
  1. //The Registry object
  2.  
  3.     SingletonRegistry theRegistry;
  4. //
  5. //The SortParms objects
  6. //
  7. //The anonymous namespace makes them publicly inaccessible outside this file.
  8. //
  9. namespace
  10. {
  11.    SortParms obj(std::string("SortParms"));       //The singleton itself
  12.    SortParms obj1(std::string("SortParmsForPerson"));    //The singleton itself
  13.    SortParms obj2(std::string("SortParmsForDate"));    //The singleton itself
  14. }
  15.  
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.

Expand|Select|Wrap|Line Numbers
  1.  
  2. int main()
  3. {
  4.    SysParms* theSysParmsSingleton;
  5.    cout << "Example B: Creating a registered singleton" << endl;
  6.  
  7.    //
  8.    //SysParms obj;  //ERROR: singleton objects cannot be created by the user
  9.    //
  10.    //Use Instance() method to locate singleton. 
  11.    theSysParmsSingleton = SysParms::Instance("SortParms");
  12.  
  13.    //
  14.    cout << "the SortParms Singleton is located at " << theSysParmsSingleton 
  15.           << endl;
  16.  
  17.    theSysParmsSingleton = SysParms::Instance("SortParmsForPerson");
  18.  
  19.    //
  20.    cout << "the SortParmsForPerson Singleton is located at "
  21.            <<   theSysParmsSingleton << endl;
  22.  
  23.    theSysParmsSingleton = SysParms::Instance("SortParmsForDate");
  24.  
  25.    //
  26.    cout << "the SortParmsForDate Singleton is located at "
  27.           << theSysParmsSingleton << endl;
  28.  
  29.    //Set a sort sequence for Person
  30.    SysParms::Instance("SortParmsForPerson")->SetParms(SysParms::ASCENDING); 
  31.    //Set a sort sequence for Date
  32.    SysParms::Instance("SortParmsForDate")->SetParms(SysParms::DESCENDING); 
  33.  
  34.    //Retrieve sort sequence
  35.    enum SysParms::Parms rval = SysParms::Instance("SortParmsForPerson")->GetParms();
  36.    if (rval == SysParms::ASCENDING)
  37.    { 
  38.       cout << "Sort Person Ascending" << endl;
  39.    }
  40.    else
  41.    {
  42.       cout << "Sort Person Descending" << endl;
  43.    }
  44.  
  45.    //Retrieve sort sequence
  46.    rval = SysParms::Instance("SortParmsForDate")->GetParms();
  47.    if (rval == SysParms::ASCENDING)
  48.    {
  49.       cout << "Sort Date Ascending" << endl;
  50.    }
  51.    else
  52.    {
  53.       cout << "Sort Date Descending" << endl;
  54.    }
  55.    return 0;
  56. }
  57.  
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
Jun 1 '07 #1
3 18235
kovik
1,044 Recognized Expert Top Contributor
The Singleton represents a replacement for a global variable. Professional C++ developers avoid global variables for a variety of reasons.
I'd just like to add that the Singleton pattern is almost as dangerous as global variables, for the same reasons, as long as you are retrieving the same object by reference.
Jul 1 '07 #2
pootle
68 New Member
You should also note that the singleton pattern as presented here is not thread safe. This is an issue when a pre-emptive kernel is involved. To make a singleton thread safe, the creation of the instance needs to be protected.
Apr 30 '08 #3
weaknessforcats
9,208 Recognized Expert Moderator Expert
You should also note that the singleton pattern as presented here is not thread safe.
That is correct. Thread safety is an issue only when multiple threads are involved and not all programs are multithreaded.

I felt is necessarry to stick with the pattern only.
May 5 '08 #4

Sign in to post your reply or Sign up for a free account.

Similar topics

4
2414
by: Neil Zanella | last post by:
Hello, I would be very interested in knowing how the following C++ multi-instance singleton (AKA Borg) design pattern based code snippet can be neatly coded in Python. While there may be somewhat unusual places where multi-instance singleton is more useful than plain singleton, it seems to me that the former leads to less coding, so unless I can somehow package the singleton pattern in a superclass (so I don't have to code it...
4
2859
by: Tony Ha | last post by:
Hello I am learning Python for in the pass ten months, and have brought a few books about Python. Most of them are good books by its only right, and all of them only teach you how to write Python programs using Python syntax and Python ways, but no one single Python book explicitly teaches you on how to analyst your application, and structure your programmes in a way, so that, it is easy to maintain, easily to reuse, (i.e. use loosely...
4
1787
by: Joakim Olesen | last post by:
Hi, I'm looking for a book/books about design patterns (factory patterns, singleton patterns etc). The book doesn't have to be aimed towards C# developers in particular, but the patterns should of course be useful in a ..Net/C# environment. I hope you can help me. Thanks in advance!
4
1923
by: Frazer | last post by:
hi are there any good samples illustrating design patterns in C#? builder, adapter, facade etc. i found a few but the reviews of that article were bad. eg http://www.codeproject.com/csharp/csdespat_1.asp#xx327127xx thnx
13
6546
by: John Salerno | last post by:
Here are a few I'm considering: Design Patterns Explained : A New Perspective on Object-Oriented Design (2nd Edition) (Software Patterns Series) by Alan Shalloway Design Patterns C# by Steven John Metsker Design Patterns by Erich Gamma Head First Design Patterns by Elisabeth Freeman
24
2091
by: John Salerno | last post by:
Since Python does so many things different, especially compared to compiled and statically typed languages, do most of the basic design patterns still apply when writing Python code? If I were to read a design pattern book (such as Head First Design Patterns), could I apply their Java examples to Python easily enough, or does Python require a different perspective when applying patterns?
22
4706
by: Krivenok Dmitry | last post by:
Hello All! I am trying to implement my own Design Patterns Library. I have read the following documentation about Observer Pattern: 1) Design Patterns by GoF Classic description of Observer. Also describes implementation via ChangeManager (Mediator + Singleton) 2) Pattern hatching by John Vlissides Describes Observer's implementation via Visitor Design Pattern. 3) Design Patterns Explained by Alan Shalloway and James Trott
6
1956
by: abcd | last post by:
I have 13 yrs experience working from Visual Studio 1.x today VS 2005 (both VB and C++) Most of the time I have worked in N-tier applications, Web applications, Windows applications....My company is a small company very limited budget..We have enterprise web products written in VB/VC++, class ASP. We have not even used .NET etc. Lots of people are talking about Design patterns, standard architecture (SOS or other IBM). I am very...
10
3646
by: vital | last post by:
Hi, I am designing the middle tier of a project. It has 6 classes and microsoft application data access block. The six classes are DBServices, Logger, ProjectServices ... etc. and all these classes talk to front-end directly. Do I need to use any design pattern in this? or what kind of design pattern is this?
0
7969
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
7886
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8272
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8035
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
6688
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5431
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
1
2404
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1494
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1238
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.