The Singleton design pattern ensures a class has only one instance and provides a global point of access to it. Here’s a concise summary of a C++ Singleton implementation and its considerations.
C++98 Singleton Implementation
In C++98, implementing a Singleton involved several steps to ensure lazy evaluation, guaranteed destruction, and thread safety. However, this approach wasn’t inherently thread-safe:
class S {
public:
static S& getInstance() {
static S instance; // Guaranteed to be destroyed, instantiated on first use
return instance;
}
private:
S() {} // Constructor needed
// C++98 method to prevent copying
S(S const&); // Don't Implement
void operator=(S const&); // Don't implement
};
C++11 Singleton Implementation
With C++11, Singleton implementation became cleaner and inherently thread-safe using the static
variable within the function scope, which is initialized in a thread-safe manner:
class S {
public:
static S& getInstance() {
static S instance; // Guaranteed to be destroyed, instantiated on first use
return instance;
}
private:
S() {} // Constructor needed
// C++11 method to prevent copying
S(S const&) = delete;
void operator=(S const&) = delete;
};
In C++11, you can delete the copy constructor and copy assignment operator to prevent copying, ensuring a single instance.
Key Points
- Lazy Evaluation: The Singleton instance is created only when it is first accessed.
- Guaranteed Destruction: The instance is automatically destroyed when the program exits, ensuring resource cleanup.
- Thread Safety: C++11 ensures that the static local variable is initialized in a thread-safe manner.
Additional Resources
- When to Use a Singleton: Singleton: How should it be used
- Initialization Order Issues:
- Lifetime of Static Variables: What is the lifetime of a static variable in a C++ function?
- Threading Implications: Singleton instance declared as static variable of GetInstance method, is it thread-safe?
- Double-Checked Locking Issue: C++ and The Perils of Double-Checked Locking
Using the Singleton pattern sparingly and understanding its implications on multithreading and resource management are crucial for robust C++ programming.