Meyer单例是C++11标准唯一保障析构时机的方案:首次调用构造,main返回后由__cxa_atexit逆序析构;须用static局部对象而非指针,析构函数轻量且禁用其他单例,依赖资源也需同法实现。

程序退出时单例对象未被销毁,导致文件句柄泄漏、数据库连接未关闭、线程卡死或段错误——这不是析构函数没写,而是你把单例放在了堆上,又只靠一个静态指针管理,C++ 标准根本不管它指向的内存。
用 Meyer 单例替代 static 指针实现自动安全析构
这是唯一由 C++11 标准强制保障析构时机的方案:构造在首次调用时发生,析构在 main() 返回后由运行时通过 __cxa_atexit 自动注册并逆序执行,不参与跨编译单元析构序列。
第一步:将 getInstance() 改为返回引用,内部声明 static Singleton instance(不是指针):
【必须是 static Singleton instance;,不能是 static Singleton* p = new Singleton();】
立即学习“C++免费学习笔记(深入)”;
第二步:确保 Singleton 类显式定义非平凡析构函数 ~Singleton(),且其中只做轻量清理——比如 close(fd)、munmap(addr)、pthread_cancel(tid),禁止调用其他单例(如 Logger::instance().log()),否则可能访问已销毁对象。
第三步:所有被该单例依赖的资源(如配置路径、线程池、日志器),也必须用同样 Meyer 方式实现;否则依赖链断裂,析构时仍会崩溃。
当必须使用堆分配时,用 std::unique_ptr 封装静态局部智能指针
适用于需传参构造、条件初始化或继承多态的场景,但关键在于存储位置——智能指针本身必须是函数作用域内的静态变量,才能获得析构保障。
方法一:正确写法(安全)
在 getInstance() 函数内声明 static std::unique_ptr
方法二:错误写法(危险)
若将 std::unique_ptr
注意:std::unique_ptr 的析构函数内部必须判空,尤其当 Singleton 构造函数抛异常导致对象未完全构建时,reset() 可能被多次调用,不判空即崩溃。
显式提供 shutdown() 接口并由业务层主动调用
当单例持有关键资源(如监听套接字、数据库连接池、工作线程)且退出流程可控时,应放弃对自动析构的依赖,把销毁权交还给宿主程序。
① 在单例类中添加 public static void shutdown(),内部使用 std::atomic
② shutdown() 中先加锁(若单例支持并发访问),再执行 delete m_instance,并立即将 m_instance 置为 nullptr。
③ getInstance() 必须检查 m_instance 是否为 nullptr,若已销毁则抛出 std::runtime_error("Singleton already shut down"),而非静默重建。
④ 宿主程序必须在 main() 返回前显式调用 Singleton::shutdown();漏掉这一步,资源必然泄漏。


















