判断单例需同时满足构造受限、获取可控、销毁明确三点:构造函数须私有且禁拷贝/移动,getinstance()须用线程安全方式返回唯一实例,且生命周期管理闭环;否则仅为命名误导。

不能靠“有没有 getInstance()”来判断一个类是不是单例——很多类写了这个函数但根本没做线程安全、没禁拷贝、也没保证唯一性,只是名字像而已。
看构造函数是否私有且禁止拷贝/赋值
真正的单例必须从源头掐断多实例可能性:
-
Singleton()构造函数必须是private或protected,否则外部能直接new Singleton()或栈上构造 - 必须显式删除拷贝和移动操作:
Singleton(const Singleton&) = delete;、Singleton& operator=(const Singleton&) = delete;(C++11 起) - 如果只删了拷贝但没删移动(比如漏了
Singleton(Singleton&&) = delete;),在启用移动语义的代码里仍可能意外生成新实例
看实例获取方式是否真正控制唯一性
光有 getInstance() 不够,得看它内部怎么实现:
- 返回局部静态变量(如
static Singleton instance;)→ 安全,C++11 起初始化线程安全,且自动析构 - 返回堆上
new出来的指针,但没加锁或没用双重检查 → 多线程下大概率崩,不是可靠单例 - 返回全局变量或静态成员指针,但没做
nullptr判空或懒初始化逻辑 → 可能根本没创建,或每次调用都 new 一个 - 如果
getInstance()返回的是值(不是引用或指针),那调用一次就拷贝一次,彻底破坏单例语义
看生命周期管理是否闭环
单例对象的销毁时机常被忽略,但直接影响资源释放和程序退出行为:
- 用局部静态变量实现的单例:析构在
main()返回后、全局对象析构阶段自动发生,安全 - 用
new+ 静态指针实现的单例:必须配套清理机制,比如用静态内嵌类的析构函数(CGarbo模式)或atexit()注册释放函数 - 若完全没处理析构(比如只
new不delete),程序退出时内存泄漏,且单例内持有的资源(文件句柄、socket、锁等)可能无法正确释放
最易被忽略的点是:即使代码看着像单例,只要没同时满足「构造受限 + 获取可控 + 销毁明确」这三点,它就只是个命名误导的普通类。尤其在跨 DLL/so 场景下,静态变量作用域分裂会让所谓“单例”在每个模块里各有一份,这时候连“唯一性”都只是幻觉。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











