C++ 单例模式实现
外观
单例模式(Singleton Pattern)是设计模式中最简单的创建型模式之一,用于确保一个类仅有一个实例,并提供一个全局访问点。该模式在需要控制资源(如数据库连接、线程池、配置管理)或确保全局一致性时非常有用。
基本概念[编辑 | 编辑源代码]
单例模式的核心思想是通过以下机制实现:
- 私有构造函数:防止外部直接实例化
- 静态私有成员变量:保存唯一实例
- 静态公有方法:提供全局访问接口
UML类图[编辑 | 编辑源代码]
基础实现[编辑 | 编辑源代码]
以下是C++中最基础的线程不安全实现:
class Singleton {
private:
static Singleton* instance;
// 私有构造函数防止外部实例化
Singleton() {}
public:
// 删除拷贝构造函数和赋值运算符
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* getInstance() {
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
void someMethod() {
// 示例方法
}
};
// 初始化静态成员
Singleton* Singleton::instance = nullptr;
线程安全实现[编辑 | 编辑源代码]
在多线程环境中,基础实现可能导致多个实例被创建。以下是改进方案:
双重检查锁定[编辑 | 编辑源代码]
#include <mutex>
class Singleton {
private:
static Singleton* instance;
static std::mutex mtx;
Singleton() {}
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton* getInstance() {
if (instance == nullptr) { // 第一次检查
std::lock_guard<std::mutex> lock(mtx);
if (instance == nullptr) { // 第二次检查
instance = new Singleton();
}
}
return instance;
}
};
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;
Meyers单例(最优实现)[编辑 | 编辑源代码]
利用局部静态变量的线程安全特性(C++11起保证):
class Singleton {
private:
Singleton() {}
public:
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
};
实际应用案例[编辑 | 编辑源代码]
配置管理器[编辑 | 编辑源代码]
游戏开发中常用单例管理全局配置:
class ConfigManager {
private:
std::unordered_map<std::string, std::string> settings;
static ConfigManager* instance;
ConfigManager() {
// 加载配置文件
settings["resolution"] = "1920x1080";
settings["volume"] = "80";
}
public:
static ConfigManager& getInstance() {
static ConfigManager instance;
return instance;
}
std::string getSetting(const std::string& key) {
return settings[key];
}
void setSetting(const std::string& key, const std::string& value) {
settings[key] = value;
}
};
日志系统[编辑 | 编辑源代码]
class Logger {
private:
std::ofstream logFile;
static Logger* instance;
Logger() {
logFile.open("app.log", std::ios::app);
}
public:
static Logger& getInstance() {
static Logger instance;
return instance;
}
void log(const std::string& message) {
logFile << "[" << getCurrentTime() << "] " << message << std::endl;
}
~Logger() {
logFile.close();
}
};
数学分析[编辑 | 编辑源代码]
单例模式的时间复杂度为,空间复杂度同样为,因为无论调用多少次getInstance()
,都只存在一个实例。
优缺点[编辑 | 编辑源代码]
优点:
- 严格控制实例数量
- 全局访问点方便管理
- 延迟初始化节省资源
缺点:
- 违反单一职责原则(管理自身生命周期)
- 单元测试困难(全局状态)
- 多线程环境下需要特殊处理
最佳实践建议[编辑 | 编辑源代码]
1. 优先使用Meyers单例(简单且线程安全) 2. 考虑是否需要单例(可能依赖注入更合适) 3. 明确生命周期管理(特别是需要清理资源时) 4. 避免在单例中保存过多状态
扩展阅读[编辑 | 编辑源代码]
- 单例模式与依赖注入的比较
- 单例在分布式系统中的挑战
- 单例模式的反模式讨论