Implementing a Reusable Singleton Template in C++
The Singleton Pattern: Restricting Object Creation
Controlling Class Instantiation
A singleton restricts a class to having only one instance through out the program's lifetime. To achieve this, the constructor must be hidden from external code:
- Declare the constructor with private access
- Provide a static member pointer to hold the single instance
- Use a static factory method to control object creation
#include <iostream>
using namespace std;
class Resource
{
static Resource* instance;
Resource();
Resource(const Resource& src);
Resource& operator=(const Resource& src);
public:
static Resource* create();
void display();
};
Resource* Resource::instance = nullptr;
Resource::Resource()
{
}
Resource* Resource::create()
{
if (instance == nullptr)
{
instance = new Resource();
}
return instance;
}
void Resource::display()
{
cout << instance << endl;
}
int main()
{
Resource* a = Resource::create();
Resource* b = Resource::create();
Resource* c = Resource::create();
a->display();
b->display();
c->display();
return 0;
}
All three pointers reference the same memory address, confirming a single instance.
Generic Singleton Template
The Problem with Manual Implementation
Each singleton class requires:
- A static instance pointer
- A static factory method
This duplication becomes tedious when many class need singleton behavior.
Solution: Extract into a Template
#ifndef SINGLETON_H
#define SINGLETON_H
template<typename T>
class Singleton
{
static T* instance;
public:
static T* getInstance();
};
template<typename T>
T* Singleton<T>::instance = nullptr;
template<typename T>
T* Singleton<T>::getInstance()
{
if (instance == nullptr)
{
instance = new T();
}
return instance;
}
#endif
Any class wanting singleton behavior simply inherits from this template:
#include <iostream>
#include "Singleton.h"
using namespace std;
class Manager
{
friend class Singleton<Manager>;
Manager();
Manager(const Manager& src);
Manager& operator=(const Manager& src);
public:
void show()
{
cout << "address = " << this << endl;
}
};
int main()
{
Manager* x = Singleton<Manager>::getInstance();
Manager* y = Singleton<Manager>::getInstance();
Manager* z = Singleton<Manager>::getInstance();
x->show();
y->show();
z->show();
return 0;
}
Key Observations
- The singleton pattern ensures one isntance per class
- The template eliminates code duplication across singleton implementations
- Friend declaration grants the template access to the class constructor
- The template handles lazy initialization automatically