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
staticfor simple lazy initialization. - Avoid storing changing business state in global singletons.
- Prefer dependency injection when testability matters.
Common Mistakes
- Using Singleton as a global variable with a fancy name. This hides dependencies and makes behavior harder to test.
- Forgetting to delete copying. A copyable singleton is not really a singleton.
- Putting too much mutable state inside it. Shared state can create order-dependent bugs.
- Using Singleton to avoid passing parameters. Explicit dependencies are usually clearer.
Quick Check
- Why is the constructor private in a Singleton?
- 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.