17370845950

C++如何创建一个单例(Singleton)类?(懒汉与饿汉模式)
C++单例模式有饿汉式和懒汉式两种:饿汉式在程序启动时构造静态常量对象,线程安全但始终存在;懒汉式推荐C++11局部静态变量实现,首次调用时构造,线程安全且延迟初始化。

单例类确保一个类在整个程序中只有一个实例,并提供全局访问点。C++ 中常用懒汉(Lazy Initialization)和饿汉(Eager Initialization)两种实现方式,核心区别在于对象创建时机:懒汉式首次调用时才构造,饿汉式在程序启动时就构造。

饿汉模式:静态成员变量 + 静态函数

利用 C++ 全局对象在 main() 之前完成初始化的特性,直接定义一个静态 const 对象。线程安全(C++11 起保证),无需加锁,但对象始终存在,哪怕从未使用过。

示例:

class Singleton {
private:
    Singleton() = default;                    // 私有构造
    Singleton(const Singleton&) = delete;     // 禁拷贝
    Singleton& operator=(const Singleton&) = delete;

public:
    static const Singleton& getInstance() {
        return instance;
    }

private:
    static const Singleton instance;  // 静态常量对象,程序加载时构造
};

// 类外定义并初始化
const Singleton Singleton::instance;

懒汉模式(线程安全版,C++11 及以后推荐)

延迟创建,首次调用 getInstance() 时才 new 出对象。C++11 标准规定:局部静态变量的初始化是线程安全的(由编译器自动加锁),因此无需手动同步,简洁又可靠。

示例:

class Singleton {
private:
    Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    static Singleton& getInstance() {
        static Singleton instance;  // 第一次调用时构造,之后直接返回
        return instance;
    }
};

懒汉模式(传统双检锁,仅用于理解或旧标准环境)

在 C++11 之前,为避免每次加锁开销,常采用“双重检查锁定(Double-Checked Locking)”,但需注意内存重排序问题,必须配合 volatile(C++11 前)或原子操作(C++11+)才能真正安全。现代 C++ 已不推荐手写此版本。

关键点:

  • 指针需声明为 static std::atomicvolatile Singleton*(旧标准)
  • 第一次判空后加锁,锁内再次判空,再创建
  • new 操作需确保内存可见性(C++11 后 atomic_store + memory_order_release)

注意事项与建议

单例不是万能解法,过度使用会增加耦合、妨碍测试。若仍需使用,请注意:

  • 析构顺序不可控:饿汉式对象在 main() 结束后销毁,懒汉式(堆分配)通常不自动析构,可考虑 atexit 注册清理函数
  • 继承单例较复杂:一般不建议继承单例类;如需多态,改用工厂或依赖注入更合适
  • 现代 C++ 优先选局部静态变量懒汉式 —— 简洁、线程安全、零成本抽象
  • 避免在构造函数中调用其他单例(可能引发初始化顺序问题)