推荐使用c++11 static局部变量实现单例:线程安全、延迟初始化、自动析构;避免饿汉式资源浪费和懒汉式线程安全风险,优先考虑依赖注入替代单例。

饿汉式单例:启动即初始化,线程安全但可能浪费资源
饿汉式在程序加载时就创建实例,天然线程安全,不用加锁,但缺点也很实在:哪怕从不调用 getInstance(),对象也会被构造。如果构造开销大(比如读配置、连数据库),或者依赖环境未就绪,就容易出问题。
常见错误现象:std::terminate 或静态初始化顺序崩溃(尤其跨编译单元引用时);构造函数抛异常导致程序直接退出。
- 必须用
static局部变量或static成员变量 +private构造函数 - 推荐用
static局部变量写法(C++11 起保证线程安全):class Singleton { public: static Singleton& getInstance() { static Singleton instance; // C++11 线程安全的延迟初始化 return instance; } Singleton(const Singleton&) = delete; Singleton& operator=(const Singleton&) = delete; private: Singleton() = default; // 可含初始化逻辑,但别 throw }; - 避免在构造函数里做不可靠操作(如文件 I/O、网络请求),否则失败无法恢复
懒汉式单例:首次调用才创建,需手动处理线程安全
懒汉式按需创建,节省资源,但多线程下极易出错——两个线程同时判断 instance == nullptr,都进去 new,结果构造两次、内存泄漏、返回不同地址。
典型错误现象:double free、use-after-free、undefined behavior,调试时偶发崩溃,难以复现。
立即学习“C++免费学习笔记(深入)”;
- 最简可用方案是加
std::mutex锁整个getInstance(),但性能差(每次调用都锁) - 推荐双重检查锁定(DCLP):
class Singleton { public: static Singleton& getInstance() { if (instance == nullptr) { std::lock_guard<std::mutex> lock(mutex_); if (instance == nullptr) { instance = new Singleton(); } } return *instance; } // ... 析构、拷贝禁用同上 private: static Singleton* instance; static std::mutex mutex_; Singleton() = default; }; Singleton* Singleton::instance = nullptr; std::mutex Singleton::mutex_; - 必须用
volatile或std::atomic修饰instance指针(C++11 后建议用std::atomic<singleton></singleton>),否则编译器重排可能导致部分构造对象被其他线程看到
现代 C++ 更推荐:用 static 局部变量替代手写懒汉
C++11 标准规定:函数内 static 局部变量的初始化是线程安全的,且只执行一次。这直接解决了懒汉式的所有痛点,代码更短、更可靠、性能更好。
使用场景:95% 的单例需求都该用这个写法,除非你必须支持 C++03 或需要显式控制销毁时机。
- 无需
std::mutex、无需new/delete、无需指针管理 - 自动满足“首次调用才构造”+“线程安全”+“自动析构”三要素
- 注意:析构发生在 main() 返回后、全局对象析构阶段,若单例依赖其他全局对象,销毁顺序可能出问题
单例的真正陷阱:生命周期与测试友好性
单例最难搞的从来不是怎么写,而是它让代码隐式依赖全局状态,导致单元测试难 mock、模块耦合高、重构成本陡增。
常见错误现象:写完单例后发现无法对 A 模块单独测(它总依赖 B 单例),或者换环境时因单例初始化顺序崩了。
- 优先考虑依赖注入:把单例对象作为参数传入,而非在函数内部硬调
Singleton::getInstance() - 如果真要单例,确保它的构造/析构不依赖其他单例,尤其避开跨 .cpp 文件的静态对象互相引用
- 避免在
main()之外的静态初始化上下文中调用getInstance()(比如全局变量初始化器里),否则行为未定义
实际项目里,static 局部变量那几行代码就够用了;但只要它开始影响测试或引发初始化顺序问题,就得回头砍掉单例,换成明确传递的对象。










