This Singleton design pattern is certainly the most known and maybe the most easiest to understand.
Its goal is to guarantee that an object will be created only once through all the program.
So this object has to be unique, can't even be created twice nor copied and it must be accessible through the entire application.
This is for example the case when you have a logging class that must be accessible by almost every class in your program.
So to resolve this problem Singleton may be the solution.
Let's discover the Singleton design pattern in this tutorial with two different implementations.
First of all
With the Singleton design pattern we have a static member function instead of a simple global static variable.
The reason is that with global or static variable we cannot be sure that another global variable will be used in another file.
Furthermore it's impossible to know in which order those variables will be instantiated or destroyed.
And another important point is that a global static variable will always be called whereas, with a static member function, if this function is never called it'll never be instantiated.
So using a static member function is an interesting solution to resolve those problems.
The code is straightforward.
We are using a protected constructor because we let possibility, to classes inheriting from the Singleton, to instantiate this Singleton.
We also set the copy constructor as private because we don't want that someone copy the Singleton instance to another address.
The first implementation could be called the classic one, because we will use new and delete keywords.
For the second one, we won't use any pointer at all, so this kind of Singleton will be shorter than the classic one.
Code of Singleton with a classic pointer (new/delete)
So main goal is to first call the public static theInstance() method in order to check if one object of type Singleton has been already created.
If we don't have a Singleton instance yet, then we create it by calling its constructor.
If there is already a Singleton instance, then we only return its instance.
This mechanism guarantees uniqueness of the Singleton object.
Furthermore within the constructor we are using the atexit() function when the program exits.
So we use the endOfProgram() callback for that which will delete the instance and reset the _instance address to 0 in order to avoid dangling pointer or bad read memory.
From begin to end: theInstance() > Constructor > exit > endOfProgram() > Destructor > _instance = 0.
The Singleton is created once and destroyed at the end of the program, so no leak.
Moreover we forbid the copy constructor to be used by setting it as private.
Singleton.h
#ifndef __BADPROG_SINGLETON_H__
#define __BADPROG_SINGLETON_H__
// Badprog.com
class Singleton
{
public:
virtual ~Singleton();
static Singleton *theInstance();
static void endOfProgram();
protected:
Singleton();
private:
Singleton(const Singleton &other);
static Singleton *_instance;
};
#endif // __BADPROG_SINGLETON_H__
Singleton.cpp
#include <iostream>
#include <cstdlib>
#include "Singleton.h"
using namespace std;
// Badprog.com
Singleton *Singleton::_instance = 0;
//-----------------------------------------------------------------------------
// Constructor.
//-----------------------------------------------------------------------------
Singleton::Singleton() {
cout << "Begin of Singleton." << endl;
atexit(&(endOfProgram));
}
//-----------------------------------------------------------------------------
// Destructor.
//-----------------------------------------------------------------------------
Singleton::~Singleton() {
cout << "End of Singleton." << endl;
}
//-----------------------------------------------------------------------------
// Destructor.
//-----------------------------------------------------------------------------
void Singleton::endOfProgram() {
delete _instance;
_instance = 0; // avoids dangling pointer and bad read memory
}
//-----------------------------------------------------------------------------
// Returns the Singleton instance.
//-----------------------------------------------------------------------------
Singleton *Singleton::theInstance() {
if (0 == _instance) {
_instance = new Singleton();
}
return _instance;
}
main.cpp
#include <iostream>
#include "Singleton.h"
using namespace std;
// Badprog.com
//-----------------------------------------------------------------------------
// Main.
//-----------------------------------------------------------------------------
int main() {
// Using instance
Singleton *s1 = Singleton::theInstance();
Singleton *s2 = Singleton::theInstance();
Singleton &s3 = *s2;
// Displaying instance adresses
cout << s1 << endl;
cout << s2 << endl;
cout << &s3 << endl;
return 0;
}
Compiling, linking and executing
g++ *.cpp -o go.exe ; ./go.exe
Result of classic Singleton
Begin of Singleton.
032ABE40
032ABE40
032ABE40
End of Singleton.
Code of Singleton without any pointer
With this kind of implementation we have no pointer so no need to free the memory at the end of the program because it will be done automatically.
Indeed this time the constructor is called statically so no memory in the heap will be allocated for that.
So each time we will enter in the theInstance() method, only the first instance of the Singleton will be used.
Furthermore we are using the delete specifier (C++11) on the copy constructor to prevent using it.
SingletonShort.h
#ifndef __BADPROG_SINGLETONSHORT_H__
#define __BADPROG_SINGLETONSHORT_H__
// Badprog.com
class SingletonShort
{
public:
virtual ~SingletonShort();
static SingletonShort &theInstance();
SingletonShort(const SingletonShort &other) = delete; // prevents classic copy
protected:
SingletonShort();
};
#endif // __BADPROG_SINGLETONSHORT_H__
SingletonShort.cpp
#include <iostream>
#include "SingletonShort.h"
using namespace std;
// Badprog.com
//-----------------------------------------------------------------------------
// Constructor.
//-----------------------------------------------------------------------------
SingletonShort::SingletonShort() {
cout << "Hello from Badprog :D" << endl;
}
//-----------------------------------------------------------------------------
// Destructor.
//-----------------------------------------------------------------------------
SingletonShort::~SingletonShort() {
cout << "Goodbye from Badprog :p" << endl;
}
//-----------------------------------------------------------------------------
// Gets instance.
//-----------------------------------------------------------------------------
SingletonShort &SingletonShort::theInstance() {
static SingletonShort uniqueInstance;
return uniqueInstance;
}
main.cpp
#include <iostream>
#include "SingletonShort.h"
using namespace std;
// Badprog.com
//-----------------------------------------------------------------------------
// Main.
//-----------------------------------------------------------------------------
int main()
{
// Using instance
SingletonShort &s1 = SingletonShort::theInstance();
SingletonShort &s2 = SingletonShort::theInstance();
// Displaying instance adresses
cout << &s1 << endl;
cout << &s2 << endl;
return 0;
}
Compiling, linking and executing
g++ *.cpp -o go.exe -std=c++1y ; ./go.exe
Result of shorter Singleton
Hello from Badprog :D
00F3D288
00F3D288
Goodbye from Badprog :p
Conclusion
The Singleton is a good entry point in the design pattern world.
Not useful in all situations, it's sometimes criticized by some programmers to be an anti-pattern.
Anyway, if you understood it, good job you did it!
Comments
Ramesh (not verified)
Wednesday, May 15, 2019 - 3:32pm
Permalink
Hii..
Hii..
I have two different classes in my project in different files. One of them is singleton class. The thing is, I want to use an object of that singleton class in the another class of my project. I've tried to do it but I got some error saying
In constructor 'name_of_non_singleton_class::its_constructor()' :
error: 'name_of_singleton_class::its_constructor()' is private
error: within this context
Mi-K
Thursday, May 16, 2019 - 11:25am
Permalink
Hello Ramesh,
Hello Ramesh,
The Singleton constructor is private, so you can't do that.
It's the principle of the Singleton, you can have only one instance of this class.
This is why you have to call it like that in one file:
SingletonShort &calledFromFile1 = SingletonShort::theInstance();
And like this on another file:
SingletonShort &calledFromFile2 = SingletonShort::theInstance();
So in every file you'll have always the same instance of the Singleton.
If you change something in file1, you'll have the same modification in file2.
Add new comment