All Courses
OOP: DESIGN PATTERNS

Singleton: When Not To Use It

Concept Definition

Singleton restricts a class so only one shared instance is available. A common C++ form uses a function-local static object inside an instance() method. The pattern is simple to write, but easy to overuse.

The analogy is a university registrar office. There may be one official office for records, but that does not mean every student, teacher, and system should secretly depend on it from anywhere.

Why It Matters

Singleton appears in many interview questions because it tests construction control, access control, static objects, and design judgment. The important lesson is not "always use Singleton." The important lesson is that global access can create hidden dependencies, make tests harder, and make program state difficult to reason about.

In professional C++, constructor injection is often cleaner: pass the dependency to the objects that need it.

Syntax Block

class AppConfig {
public:
    static AppConfig& instance();     // one global access point

private:
    AppConfig() = default;            // outside code cannot construct
};

Explained Code

Example: Local Static Singleton

#include <string> // std::string

class AppConfig {
private:
    std::string appName = "OOP Course";        // shared configuration value

    AppConfig() = default;                     // block direct construction

public:
    AppConfig(const AppConfig&) = delete;      // block copying
    AppConfig& operator=(const AppConfig&) = delete; // block assignment

    static AppConfig& instance() {
        static AppConfig config;               // created once on first call
        return config;                         // return same object each time
    }

    std::string name() const { return appName; } // read configuration
};

This form is often called a Meyers Singleton. It is compact, but the design question remains: should this dependency really be globally reachable?

Singleton vs Dependency Injection

Feature Singleton Dependency injection
Access Global access through instance() Passed explicitly to constructors or functions
Testing Harder to replace shared state Easier to pass a fake object
Coupling Hidden dependency Visible dependency
Use when Exactly one process-wide object is truly needed Most normal service dependencies

Key Points / Rules

  • Use Singleton rarely and only when one shared instance is a real requirement.
  • Delete copy construction and copy assignment to prevent extra instances.
  • Prefer function-local static for simple lazy initialization.
  • Avoid storing changing business state in global singletons.
  • Prefer dependency injection when testability matters.

Common Mistakes

  1. Using Singleton as a global variable with a fancy name. This hides dependencies and makes behavior harder to test.
  2. Forgetting to delete copying. A copyable singleton is not really a singleton.
  3. Putting too much mutable state inside it. Shared state can create order-dependent bugs.
  4. Using Singleton to avoid passing parameters. Explicit dependencies are usually clearer.

Quick Check

  1. Why is the constructor private in a Singleton?
  2. Why can Singleton make unit tests harder?

Viva Answer

Singleton ensures one shared instance and provides a global access point. It should be used carefully because it can hide dependencies and make tests difficult; dependency injection is often better.