Singleton Pattern

The Singleton design pattern ensures that a class has only one instance and provides a global point of access to that instance. It is a creational design pattern that is commonly used when you want to ensure that there is only one instance of a class throughout the entire application, and that instance is shared among multiple components.

Singleton Pattern C++:

#include <iostream>

class Singleton {
private:
    // Private constructor to prevent direct instantiation
    Singleton() {}

    // The single instance of the class
    static Singleton* instance;

public:
    // Public method to access the single instance
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// Initializing the static member variable 'instance'
Singleton* Singleton::instance = nullptr;

int main() {
    // Get the single instance of Singleton
    Singleton* singleton1 = Singleton::getInstance();
    Singleton* singleton2 = Singleton::getInstance();

    // Both 'singleton1' and 'singleton2' point to the same instance of Singleton.
    singleton1->showMessage(); // Output: Hello from Singleton!
    singleton2->showMessage(); // Output: Hello from Singleton!

    return 0;
}

Explanation:
In the code above, we have implemented the Singleton pattern using a static method getInstance() that returns the single instance of the Singleton class. The constructor of the Singleton class is made private to prevent direct instantiation of the class from outside.

The static member variable instance is used to store the single instance of the class. When the getInstance() method is called, it checks if the instance is already created. If not, it creates a new instance of the Singleton class and returns it. If the instance is already created, it simply returns the existing instance.

In the main() function, we demonstrate how to use the Singleton pattern. We call the getInstance() method twice, and both times, it returns the same instance of the Singleton class. Therefore, singleton1 and singleton2 point to the same memory location, confirming that there is only one instance of the Singleton class throughout the application.

Advantages of Singleton Pattern:

  1. Provides a global access point to the single instance, ensuring that the instance is easily accessible from anywhere in the codebase.
  2. Guarantees that there is only one instance of the class, preventing multiple instantiations and reducing memory overhead.
  3. Supports lazy initialization, meaning the instance is created only when it is first requested, which can improve performance in certain scenarios.

Disadvantages of Singleton Pattern:

  1. May violate the Single Responsibility Principle by combining object creation with other responsibilities.
  2. Can introduce tight coupling and make testing more difficult.
  3. In a multi-threaded environment, special consideration is required to ensure thread-safety during instance creation.

In summary, the Singleton pattern is a useful design pattern when you want to ensure there is only one instance of a class throughout the application. By using the Singleton pattern, you can control object creation and access more effectively, promoting code reusability and reducing resource usage.

Thread Safe Singleton C++

To make the above Singleton pattern implementation thread-safe, we need to address the issue of multiple threads potentially accessing the getInstance() method simultaneously and creating multiple instances. There are various ways to achieve thread safety in Singleton pattern implementation. One common approach is using Double-Checked Locking with Mutex. Here’s the updated code with thread safety:

#include <iostream>
#include <mutex>

class Singleton {
private:
    // Private constructor to prevent direct instantiation
    Singleton() {}

    // The single instance of the class
    static Singleton* instance;

    // Mutex for thread safety
    static std::mutex mtx;

public:
    // Public method to access the single instance
    static Singleton* getInstance() {
        // Double-Checked Locking with Mutex
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mtx); // Lock the mutex
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    void showMessage() {
        std::cout << "Hello from Singleton!" << std::endl;
    }
};

// Initializing the static member variable 'instance'
Singleton* Singleton::instance = nullptr;

// Initializing the static member variable 'mtx'
std::mutex Singleton::mtx;

int main() {
    // Get the single instance of Singleton
    Singleton* singleton1 = Singleton::getInstance();
    Singleton* singleton2 = Singleton::getInstance();

    singleton1->showMessage(); // Output: Hello from Singleton!
    singleton2->showMessage(); // Output: Hello from Singleton!

    return 0;
}

Explanation:
In the updated code, we have added a static member variable mtx, which is a std::mutex that provides mutual exclusion to ensure thread safety. The getInstance() method now uses Double-Checked Locking with Mutex to minimize the overhead of locking.

When a thread enters the getInstance() method, it checks if the instance is already created (the first check). If it is not created, the thread acquires the lock on the mtx mutex, and then rechecks the instance variable to ensure that no other thread has created the instance in the meantime (the second check). If the instance is still nullptr, the thread creates the singleton instance. This way, we ensure that only one thread creates the instance while other threads wait for the mutex to be released.

Using the Double-Checked Locking with Mutex approach, we achieve thread safety while also minimizing the performance impact of locking by only locking when necessary.

With this modification, the Singleton pattern implementation is thread-safe, and multiple threads can safely access the getInstance() method without creating multiple instances.

Leave a Reply