Singleton Pattern
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 91 of 104.
The Singleton pattern ensures that a class has only one instance throughout the entire program and provides a global point of access to it. This is useful for resources that should be shared, like a configuration manager, logger, or database connection pool.
The key idea is to make the constructor private so no one can create instances directly, then provide a static method that returns the single instance:
#include <iostream>
#include <string>
class Logger {
private:
std::string logFile;
// Private constructor - prevents direct instantiation
Logger() : logFile("app.log") {}
// Delete copy constructor and assignment operator
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
public:
// Static method to access the single instance
static Logger& getInstance() {
static Logger instance; // Created once, lives until program ends
return instance;
}
void log(const std::string& message) {
std::cout << "[LOG] " << message << "\n";
}
};
int main() {
Logger::getInstance().log("Application started");
Logger& logger = Logger::getInstance();
logger.log("Processing data");
}The static Logger instance inside getInstance() is a C++11 feature called "magic statics" - it's thread-safe and guaranteed to be initialized only once. By deleting the copy constructor and assignment operator, we prevent anyone from creating copies of our singleton.
Use Singleton sparingly - it introduces global state which can make testing harder. It's best suited for truly shared resources where having multiple instances would cause problems.
Challenge
EasyLet's build a GameSettings singleton that manages configuration for a game application. This is a perfect use case for the Singleton pattern—you want exactly one settings manager that all parts of your game can access, ensuring consistent configuration throughout.
You'll organize your code across three files:
GameSettings.h: Define your singleton class that manages game configuration.Your
GameSettingsclass should store three settings as private members:difficulty(string),volume(integer from 0-100), andfullscreen(boolean). Initialize them with default values:"Normal",50, andfalse.Implement the Singleton pattern properly:
- Make the constructor private
- Delete the copy constructor and assignment operator
- Provide a static
getInstance()method that returns a reference to the single instance
Add these public methods to interact with the settings:
setDifficulty(const std::string& diff)— updates the difficultysetVolume(int vol)— updates the volumesetFullscreen(bool fs)— updates the fullscreen modedisplaySettings()— prints all current settings
GameModule.h: Create a separate module that accesses the singleton.Define a function called
applyGamePresetthat takes a preset name (string). This function should access theGameSettingssingleton and configure it based on the preset:"casual"— sets difficulty to"Easy", volume to70, fullscreen tofalse"competitive"— sets difficulty to"Hard", volume to30, fullscreen totrue- Any other preset — keeps the default settings unchanged
This demonstrates how different parts of a program can access and modify the same singleton instance.
main.cpp: Bring everything together to show the singleton in action.Read two inputs:
- A preset name (string)
- A custom volume level (integer)
First, display the initial default settings by calling
displaySettings()on the singleton. Print a blank line after.Then apply the preset using your
applyGamePresetfunction and display the settings again. Print a blank line after.Finally, override just the volume with the custom input value and display the final settings.
The displaySettings() method should output in this exact format:
Difficulty: [value]
Volume: [value]
Fullscreen: [yes/no]For example, with inputs casual and 85:
Difficulty: Normal
Volume: 50
Fullscreen: no
Difficulty: Easy
Volume: 70
Fullscreen: no
Difficulty: Easy
Volume: 85
Fullscreen: noWith inputs competitive and 20:
Difficulty: Normal
Volume: 50
Fullscreen: no
Difficulty: Hard
Volume: 30
Fullscreen: yes
Difficulty: Hard
Volume: 20
Fullscreen: yesNotice how both main.cpp and GameModule.h access the same singleton instance—changes made in one place are visible everywhere. This is the power of the Singleton pattern for shared resources like game settings.
Cheat sheet
The Singleton pattern ensures a class has only one instance throughout the program and provides global access to it. It's useful for shared resources like configuration managers, loggers, or database connection pools.
Key implementation steps:
- Make the constructor private to prevent direct instantiation
- Delete the copy constructor and assignment operator to prevent copies
- Provide a static method that returns a reference to the single instance
class Logger {
private:
std::string logFile;
// Private constructor
Logger() : logFile("app.log") {}
// Delete copy constructor and assignment operator
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
public:
// Static method to access the single instance
static Logger& getInstance() {
static Logger instance; // Created once, lives until program ends
return instance;
}
void log(const std::string& message) {
std::cout << "[LOG] " << message << "\n";
}
};
// Usage
Logger::getInstance().log("Application started");
Logger& logger = Logger::getInstance();
logger.log("Processing data");The static Logger instance inside getInstance() uses C++11 "magic statics"—it's thread-safe and guaranteed to be initialized only once.
Use Singleton sparingly as it introduces global state which can make testing harder. Best suited for truly shared resources where multiple instances would cause problems.
Try it yourself
#include <iostream>
#include <string>
#include "GameSettings.h"
#include "GameModule.h"
using namespace std;
int main() {
// Read inputs
string presetName;
int customVolume;
cin >> presetName;
cin >> customVolume;
// TODO: Get the GameSettings singleton instance
// TODO: Display initial default settings
// TODO: Print a blank line
// TODO: Apply the preset using applyGamePreset function
// TODO: Display settings after applying preset
// TODO: Print a blank line
// TODO: Override the volume with customVolume
// TODO: Display final settings
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy10STL Overview
STL Overview & PhilosophySTL ContainersIteratorsSTL AlgorithmsFunctors & Lambda ExpressionsRecap - Word Frequency13Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory & Abstract FactoryBuilder PatternObserver PatternStrategy Pattern2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container