Singleton Pattern in C++



A Singleton Pattern is a design pattern which allows to create only one object of a class. Instead of allowing the class to create multiple instances everytime it is called, the singleton pattern ensures that only one instance of the class is created and it also provides it a global access point so that it can be accessed from anywhere in the code.

The singleton pattern is useful when exactly one object is needed to coordinate actions across the system. For example, imagine you are in a office and you need to use a printer. Instead of having printer for a each employee, you can have a single printer that is shared by all employees. This way, you can ensure that only one person can use the printer at a time and it also saves resources.

Key Points of Singleton Pattern

Following are the key points of Singleton Pattern −

  • It restricts the instantiation of a class to one single instance.
  • It provides a global access point to that instance.
  • It is often used for managing shared resources such as database connections, configuration settings, logging, etc.
  • It can be implemented using lazy initialization, where the instance is created only when it is needed for the first time.

Implementation of Singleton Pattern in C++

There are several ways to implement the Singleton Pattern in C++. Some of the important and common implementations are −

  • Lazy Initialization Singleton
  • Eager Initialization Singleton (Hungry Singleton)
  • Mayers' Singleton

Mostly, the lazy initialization singleton is used as it is more efficient and it also saves memory. However, the eager initialization singleton is simpler and it is also thread-safe. The Mayers' singleton implementation is a very good modern approach for creating singleton classes in C++.

Lazy Initialization Singleton

In this approach, the instance of the class is created only when it is needed for the first time. This can help us in creating only one instance of the class and it also saves memory.

Step to implement Singleton Pattern in C++

Following are the steps to implement Singleton Pattern in C++ −

  • Make the constructor of the class private so that it cannot be instantiated from outside the class.
  • Then, create a static variable that holds the single instance of the class.
  • Create a static method that returns the instance of the class. This method checks if the instance is already created, if not it creates one and returns it. Otherwise, it simply returns the existing instance.

Example of Singleton Pattern in C++

In the below example, we have a Logger class that implements the singleton pattern. The getInstance() method returns the single instance of the Logger class. The log() method is used to log messages.

Let's implement a simple Logger class using Singleton Pattern in C++.

#include <iostream>
#include <string>
using namespace std;
// Lazy Initialization Singleton of Logger
class Logger {
   private:
      static Logger* instance;
      Logger() {} 
   
   public:
      static Logger* getInstance() {
         if (instance == nullptr) {
            instance = new Logger();
         }
         return instance;
      }
      
      void log(string message) {
         cout << "Log: " << message << endl;
      }
};
// Initialize the static member
Logger* Logger::instance = nullptr;

// Main function
int main() {
   Logger* logger = Logger::getInstance();
   logger->log("This is a log message.");
   Logger* l1 = Logger::getInstance();
   l1->log("This is another log message.");
   return 0;
}

Following is the output of the above program −

Log: This is a log message.
Log: This is another log message.

Eager Initialization Singleton(Hungry Singleton) Implementation

In this approach, we create the instance of the class at the time of class loading. This approach is simpler and it is also thread-safe. However, there is a drawback of this approach is that the instance is created even if it is not used, which can lead to resource wastage. So if you are sure that the instance will be used, then this approach is a good choice.

Example of Eager Initialization Singleton Pattern in C++

Let's implement a simple Logger class using Eager Initialization Singleton Pattern in C++.

#include <iostream>
#include <string>
using namespace std;

// Eager Initialization Singleton of Logger
class Logger {
   private:
      static Logger* instance;
      Logger() {} 
   
   public:
      static Logger* getInstance() {
         return instance;
      }
      
      void log(string message) {
         cout << "Log: " << message << endl;
      }
};
// Initialize the instance at the time of class loading
Logger* Logger::instance = new Logger();

// Main function
int main() {
   Logger* logger = Logger::getInstance();
   logger->log("This is a log message.");
   Logger* l1 = Logger::getInstance();
   l1->log("This is another log message.");
   return 0;
}

Following is the output of the above program −

Log: This is a log message.
Log: This is another log message.

Mayers' Singleton Implementation

The Mayers' Singleton implementation is a very good modern approach for creating singleton classes in C++. This approach uses a static local variable inside the getInstance() method to hold the single instance of the class. The instance is created when the method is called for the first time and it is destroyed automatically when the program exits. This approach is thread-safe and it also ensures that only one instance of the class is created.

Example of Mayers' Singleton Pattern in C++

Let's implement a simple Logger class using Mayers' Singleton Pattern in C++.

#include <iostream>
#include <string>
using namespace std;

// Mayers' Singleton of Logger
class Logger {
   private:
      Logger() {} 
   
   public:
      static Logger& getInstance() {
         static Logger instance;
         return instance;
      }
      
      void log(string message) {
         cout << "Log: " << message << endl;
      }
};
 // Main function
int main() {
   Logger& logger = Logger::getInstance();
   logger.log("This is a log message.");
   Logger& l1 = Logger::getInstance();
   l1.log("This is another log message.");
   return 0;
}

Following is the output of the above program −

Log: This is a log message.
Log: This is another log message.

Real-world use cases of Singleton Pattern

Following are some real-world use cases of Singleton Pattern −

  • Logger class − As we have seen in the examples, the logger class uses the singleton pattern, so it can be accessed anywhere but creates only one instance throughout the application.
  • Configuration class − A configuration class can be implemented as a singleton to ensure that there is only one instance of the configuration settings throughout the application.
  • Database connection class − Another usecase is to implement a database connection class, so that you don't need to create multiple connections to the database.
  • Printer Spooler − A printer spooler can be implemented as a singleton to manage print jobs in a centralized manner. So, your whole system has only one instance of the printer spooler instead of making multiple instances for every application on the system.

Conclusion

In this chapter, we covered in detail the Singleton Pattern in C++. We explained how to implement it and also provided an example of a Logger class that uses the singleton pattern. The singleton pattern is a useful design pattern which helps in managing shared resources and it also ensures that only one instance of a class is created.

Advertisements