C++ 单例模式
外观
C++单例模式[编辑 | 编辑源代码]
单例模式(Singleton Pattern)是软件工程中一种常用的设计模式,属于创建型模式的一种。它确保一个类只有一个实例,并提供一个全局访问点。单例模式通常用于管理共享资源,如配置管理、日志记录或数据库连接等。
介绍[编辑 | 编辑源代码]
单例模式的核心思想是限制类的实例化次数,确保在整个程序运行期间仅存在一个实例。这在以下场景中非常有用:
- 需要控制资源访问(如文件系统或数据库连接)。
- 需要全局状态管理(如应用程序配置)。
- 需要共享数据或服务(如缓存管理器)。
单例模式的特点[编辑 | 编辑源代码]
- 私有构造函数:防止外部直接实例化。
- 静态成员变量:存储唯一实例。
- 静态访问方法:提供全局访问点(如 `getInstance()`)。
- 线程安全(可选):确保多线程环境下仅创建一个实例。
实现方式[编辑 | 编辑源代码]
基础实现(非线程安全)[编辑 | 编辑源代码]
以下是一个最简单的单例模式实现,但仅适用于单线程环境:
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 doSomething() {
std::cout << "Singleton is doing something." << std::endl;
}
};
// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;
使用示例:
int main() {
Singleton* singleton = Singleton::getInstance();
singleton->doSomething();
return 0;
}
输出:
Singleton is doing something.
线程安全实现(C++11及以上)[编辑 | 编辑源代码]
在多线程环境中,上述实现可能导致多个实例被创建。以下是线程安全的实现方式:
#include <mutex>
class ThreadSafeSingleton {
private:
static ThreadSafeSingleton* instance;
static std::mutex mtx; // 互斥锁,确保线程安全
ThreadSafeSingleton() {} // 私有构造函数
public:
ThreadSafeSingleton(const ThreadSafeSingleton&) = delete;
ThreadSafeSingleton& operator=(const ThreadSafeSingleton&) = delete;
static ThreadSafeSingleton* getInstance() {
std::lock_guard<std::mutex> lock(mtx); // 加锁
if (instance == nullptr) {
instance = new ThreadSafeSingleton();
}
return instance;
}
};
// 初始化静态成员变量
ThreadSafeSingleton* ThreadSafeSingleton::instance = nullptr;
std::mutex ThreadSafeSingleton::mtx;
更高效的线程安全实现(Meyer's Singleton)[编辑 | 编辑源代码]
C++11 引入了静态局部变量的线程安全特性,可以利用这一点简化实现:
class MeyersSingleton {
private:
MeyersSingleton() {} // 私有构造函数
public:
MeyersSingleton(const MeyersSingleton&) = delete;
MeyersSingleton& operator=(const MeyersSingleton&) = delete;
static MeyersSingleton& getInstance() {
static MeyersSingleton instance; // 线程安全,C++11保证
return instance;
}
};
实际应用案例[编辑 | 编辑源代码]
日志管理器[编辑 | 编辑源代码]
单例模式常用于日志系统,确保所有日志消息通过同一个实例写入文件:
class Logger {
private:
static Logger* instance;
std::ofstream logFile;
Logger() {
logFile.open("app.log", std::ios::app);
}
public:
static Logger* getInstance() {
if (instance == nullptr) {
instance = new Logger();
}
return instance;
}
void log(const std::string& message) {
logFile << message << std::endl;
}
~Logger() {
logFile.close();
}
};
Logger* Logger::instance = nullptr;
使用示例:
int main() {
Logger::getInstance()->log("Application started");
Logger::getInstance()->log("Performing task...");
return 0;
}
配置管理器[编辑 | 编辑源代码]
单例模式也适用于全局配置管理:
#include <unordered_map>
class ConfigManager {
private:
static ConfigManager* instance;
std::unordered_map<std::string, std::string> config;
ConfigManager() {
// 加载默认配置
config["theme"] = "dark";
config["language"] = "en";
}
public:
static ConfigManager* getInstance() {
if (instance == nullptr) {
instance = new ConfigManager();
}
return instance;
}
std::string getConfig(const std::string& key) {
return config[key];
}
void setConfig(const std::string& key, const std::string& value) {
config[key] = value;
}
};
ConfigManager* ConfigManager::instance = nullptr;
单例模式的优缺点[编辑 | 编辑源代码]
优点[编辑 | 编辑源代码]
- 提供对唯一实例的受控访问。
- 避免全局变量污染命名空间。
- 支持延迟初始化(Lazy Initialization)。
缺点[编辑 | 编辑源代码]
- 违反单一职责原则(管理自身生命周期)。
- 可能导致代码耦合度高。
- 难以进行单元测试(由于全局状态)。
- 多线程环境下需要额外处理。
类图[编辑 | 编辑源代码]
以下是单例模式的类图表示:
数学表示[编辑 | 编辑源代码]
单例模式可以形式化表示为:
总结[编辑 | 编辑源代码]
单例模式是C++中一种重要的设计模式,用于确保类只有一个实例并提供全局访问点。虽然实现简单,但在多线程环境中需要特别注意线程安全问题。现代C++(C++11及以上)提供了更简洁的线程安全实现方式。开发者应谨慎使用单例模式,避免过度使用导致代码难以维护。
对于初学者,建议从基础的单线程实现开始理解概念,再逐步学习线程安全版本。高级开发者可以考虑依赖注入等替代方案,以改善代码的可测试性和模块化程度。