1. 单例模式的核心价值与应用场景
单例模式作为创建型设计模式的经典代表,在C++开发中扮演着重要角色。我第一次接触单例是在一个需要全局配置管理的项目中,当时多个模块都需要读取同一份配置数据,如果每个模块都自己实例化配置对象,不仅浪费内存,更会导致配置不一致的问题。单例模式完美解决了这个痛点。
1.1 为什么需要单例模式
在以下三种典型场景中,单例模式的价值尤为突出:
- 资源共享:日志系统、数据库连接池这类需要全局唯一访问点的资源
- 配置管理:应用程序的全局配置信息需要保证一致性
- 控制访问:如线程池、任务管理器等需要集中控制的组件
注意:不要滥用单例模式。我曾见过有人把工具类也做成单例,这反而增加了代码耦合度。只有当确实需要控制实例数量时,才应该考虑单例。
1.2 单例模式的UML结构与核心要素
标准的单例模式包含三个关键设计:
- 私有化构造函数(防止外部实例化)
- 静态成员变量保存唯一实例
- 静态方法提供全局访问点
cpp复制class Singleton {
private:
static Singleton* instance; // 静态成员变量
Singleton() {} // 私有构造函数
public:
static Singleton* getInstance() { // 静态访问方法
if (instance == nullptr) {
instance = new Singleton();
}
return instance;
}
};
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. C++单例模式的五种实现方式演进
2.1 基础版本:懒汉式(线程不安全)
这是最简单的实现,但存在明显的线程安全问题:
cpp复制class LazySingleton {
private:
static LazySingleton* instance;
LazySingleton() {}
public:
static LazySingleton* getInstance() {
if (!instance) { // 竞态条件可能发生在这里
instance = new LazySingleton();
}
return instance;
}
};
我在早期项目中使用过这种实现,结果在多线程环境下出现了重复创建实例的问题。当两个线程同时检查instance == nullptr时,都会认为需要创建新实例。
2.2 线程安全版本:加锁的懒汉式
为了解决线程安全问题,最直接的方法是引入互斥锁:
cpp复制#include <mutex>
class ThreadSafeSingleton {
private:
static ThreadSafeSingleton* instance;
static std::mutex mtx;
ThreadSafeSingleton() {}
public:
static ThreadSafeSingleton* getInstance() {
std::lock_guard<std::mutex> lock(mtx); // 加锁
if (!instance) {
