CreationalC++verifiedVerified
Singleton Pattern in C++
Ensures a class has only one instance and provides a global point of access to it.
How to Implement the Singleton Pattern in C++
1Step 1: Define the Singleton with deleted copy/move constructors
class AppConfig {
public:
static AppConfig& instance() {
static AppConfig inst;
return inst;
}
void set(const std::string& key, const std::string& value) {
data_[key] = value;
}
std::string get(const std::string& key) const {
auto it = data_.find(key);
return it != data_.end() ? it->second : "";
}2Step 2: Prevent copying and moving
AppConfig(const AppConfig&) = delete;
AppConfig& operator=(const AppConfig&) = delete;
private:
AppConfig() = default;
std::map<std::string, std::string> data_;
};3Step 3: Demonstrate usage
int main() {
AppConfig::instance().set("db_host", "localhost");
std::cout << AppConfig::instance().get("db_host") << "\n";
}#include <iostream>
#include <string>
#include <map>
#include <mutex>
#include <shared_mutex>
#include <stdexcept>
#include <format>
#include <optional>
// [step] Thread-safe Singleton with read-write locking
class ConfigManager {
public:
// Meyer's Singleton - guaranteed thread-safe in C++11+
static ConfigManager& instance() {
static ConfigManager inst;
return inst;
}
// [step] Thread-safe read with shared lock
std::optional<std::string> get(const std::string& key) const {
std::shared_lock lock(mu_);
auto it = data_.find(key);
if (it == data_.end()) return std::nullopt;
return it->second;
}
std::string getOrThrow(const std::string& key) const {
auto val = get(key);
if (!val) throw std::runtime_error(
std::format("Config key '{}' not found", key));
return *val;
}
// [step] Thread-safe write with exclusive lock
void set(const std::string& key, std::string value) {
std::unique_lock lock(mu_);
data_[key] = std::move(value);
}
bool contains(const std::string& key) const {
std::shared_lock lock(mu_);
return data_.contains(key);
}
void remove(const std::string& key) {
std::unique_lock lock(mu_);
data_.erase(key);
}
size_t size() const {
std::shared_lock lock(mu_);
return data_.size();
}
// [step] Prevent copy, move, and external construction
ConfigManager(const ConfigManager&) = delete;
ConfigManager& operator=(const ConfigManager&) = delete;
ConfigManager(ConfigManager&&) = delete;
ConfigManager& operator=(ConfigManager&&) = delete;
private:
ConfigManager() = default;
~ConfigManager() = default;
mutable std::shared_mutex mu_;
std::map<std::string, std::string> data_;
};
// [step] Demonstrate thread-safe usage
int main() {
auto& config = ConfigManager::instance();
config.set("db.host", "localhost");
config.set("db.port", "5432");
std::cout << std::format("host={}, port={}\n",
config.getOrThrow("db.host"),
config.getOrThrow("db.port"));
std::cout << std::format("has db.host: {}\n", config.contains("db.host"));
std::cout << std::format("size: {}\n", config.size());
}Singleton Pattern Architecture
hourglass_empty
Rendering diagram...
lightbulb
Singleton Pattern in the Real World
“Think of a country’s president. There can only be one at any time. When anyone needs to communicate with the president, they don’t create a new one—they access the existing one through the official channel (the static method).”