📌深入 C++ 单例模式:原理、实现方式对比与 shared_ptr 架构设计
📌深入 C++ 单例模式:原理、实现方式对比与 shared_ptr 架构设计
1️⃣ 什么是单例?基本语义与使用场景
单例([[Singleton]])是对象创建模式中最常见的一种,其目标是确保类在系统中只有一个实例,并提供全局访问入口。
✅ 常见使用场景:
- 配置中心(ConfigManager)
- 日志系统(Logger)
- 资源池(如内存池、线程池)
- 调度器、会话管理器
- 框架注册表、插件系统
2️⃣ 单例的五种常见实现方式
推荐使用方式:
- 懒汉式 + 线程安全(C++11 标准)局部静态变量(Meyers Singleton)— 【推荐使用】
- shared_ptr 单例(更灵活)
🍃1. 饿汉式单例(Early Instantiation)
class Singleton {
public:
static Singleton& instance() {
return inst;
}
private:
Singleton() {}
static Singleton inst;
};
Singleton Singleton::inst;
- ✅ 简单易懂,线程安全(由 C++ 静态对象初始化保障)
- ❌ 资源可能浪费,程序启动就构造实例
🍃2. 懒汉式(Lazy Initialization)+ 非线程安全
class Singleton {
public:
static Singleton* getInstance() {
if (!instance_)
instance_ = new Singleton;
return instance_;
}
private:
Singleton() {}
static Singleton* instance_;
};
Singleton* Singleton::instance_ = nullptr;
- ✅ 仅在需要时创建实例
- ❌ 非线程安全,多个线程可能同时构造多个实例
🍃3. 懒汉式 + 线程安全(C++11 标准)局部静态变量(Meyers Singleton)— 【推荐使用】
class Singleton {
public:
static Singleton& instance() {
static Singleton inst; // C++11 保证线程安全
return inst;
}
private:
Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
- ✅ 推荐使用:线程安全、懒加载、无锁开销
- ✅ 析构自动管理,依赖 C++ 静态局部变量特性
- ❗ 禁止拷贝构造、赋值运算,防止实例复制
- ✅ 最简洁、安全、高效的方式(默认推荐)
后面会有这种方式的语法语义与底层源码解析
🍃4. 懒汉式 + 双重检查锁(DCLP Double-Checked Locking)
class Singleton {
public:
static Singleton* instance() {
if (!inst) {
std::lock_guard<std::mutex> lock(mtx);
if (!inst) inst = new Singleton;
}
return inst;
}
private:
static Singleton* inst;
static std::mutex mtx;
};
- ✅ 懒加载,适用于需要动态构造析构控制的场景
- ❌ 实现复杂,容易出错
- ⚠️ 在 C++11 前实现容易出错(缺乏内存屏障)
🍃5. 智能指针 + 延迟构造
class Singleton {
public:
static std::shared_ptr<Singleton> instance() {
static std::shared_ptr<Singleton> inst(new Singleton);
return inst;
}
};
支持自定义析构、更适合资源生命周期管理
🍃6. 模板化 shared_ptr 单例(进阶)— 现代 C++ 的正确打开方式
template <typename T>
class SharedSingleton {
public:
using Ptr = std::shared_ptr<T>;
static void setDeleter(std::function<void(T*)> deleter) {
getDeleter() = std::move(deleter);
}
template<typename... Args>
static Ptr instance(Args&&... args) {
std::call_once(getOnceFlag(), [&] {
instance_() = Ptr(new T(std::forward<Args>(args)...), getDeleter());
});
return instance_();
}
static void reset() {
std::lock_guard<std::mutex> lock(getMutex());
instance_().reset();
getOnceFlag() = std::once_flag();
}
private:
static Ptr& instance_() {
static Ptr inst;
return inst;
}
static std::once_flag& getOnceFlag() {
static std::once_flag flag;
return flag;
}
static std::mutex& getMutex() {
static std::mutex mtx;
return mtx;
}
static std::function<void(T*)>& getDeleter() {
static std::function<void(T*)> deleter = [](T* p) { delete p; };
return deleter;
}
};
3️⃣ 实现方式对比分析
实现方式 | 构造控制 | 析构控制 | 支持传参 | 线程安全 | 生命周期可控 | 工程推荐度 |
---|---|---|---|---|---|---|
饿汉式 | ❌ | ❌ | ❌ | ✅ | ❌ | 🟡 |
懒汉式+DCLP | ✅ | ❌ | ❌ | ⚠️ | ❌ | ❌(风险大) |
Meyers Singleton | ✅ | ❌ | ❌ | ✅(C++11) | ❌ | ✅ |
shared_ptr静态 | ✅ | ✅ | ❌ | ✅ | 部分 | ✅ |
shared_ptr模板封装 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅✅✅ |
4️⃣ 懒汉式 + 线程安全(C++11 标准)局部静态变量(Meyers Singleton)— 语法语义与底层源码解析
🍃局部静态变量的线程安全(C++11)
static Singleton& getInstance() {
static Singleton instance;
return instance;
}
C++11 标准 [stmt.dcl/4]
:[[局部静态变量的初始化]]是[[线程安全]]的。
[[编译器]]在初始化前加锁,保证只有一个线程可以构造它。
编译器生成等价伪代码(示意):
Singleton& getInstance() {
static bool initialized = false;
static char storage[sizeof(Singleton)];
static std::once_flag flag;
std::call_once(flag, [&] {
new (&storage) Singleton();
initialized = true;
});
return *reinterpret_cast<Singleton*>(&storage);
}
🍃析构顺序与静态对象生命周期问题
- 局部
static
实例会在main()
退出后被自动[[析构]] - 如果你希望手动控制生命周期(如
exit()
后仍然存在),需配合new
与atexit
或shared_ptr
实现。
🍃源码级剖析(glibc + clang libc++)
[[glibc]] 层面:pthread_once
实现
[[glibc]] 中 std::call_once
依赖 pthread_once
:
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
pthread_once
使用锁 + 状态标志 + [[memory barrier]] 保证只初始化一次
是 [[C++11]] std::call_once
的基础
[[libc++]] 实现(<mutex>
)
namespace std {
template<class Callable>
void call_once(once_flag& flag, Callable&& f);
}
内部采用了双状态原子标记(__called
, __complete
)
GCC 实现中使用 __atomic_load_n
+ __sync_bool_compare_and_swap
保证[[原子性]]
5️⃣ 底层原理解析:语义 + ABI 行为 + 构造顺序
🧵 std::call_once
+ std::once_flag
static std::once_flag f;
std::call_once(f, [] { singleton = new Singleton(); });
🔥 内存模型分析
- 局部 static:存储于静态区
- shared_ptr:堆区资源,引用计数释放
6️⃣ ResourcePool / ThreadPool 工程实践
auto pool = SharedSingleton<BufferPool>::instance(32, 8*1024);
auto buf = pool->acquire();
auto pool = SharedSingleton<ThreadPool>::instance(8);
pool->enqueue([] { do_work(); });
✅ 总结与设计哲学
能力点 | Meyers Singleton | shared_ptr 封装 |
---|---|---|
安全性 | ✅ | ✅ |
灵活性 | ❌ | ✅✅ |
生命周期控制 | ❌ | ✅✅✅ |
测试友好性 | ❌ | ✅✅ |
工程适配度 | 🟡 | ✅✅✅ |