《C++ 单例模式》

  在 C++ 中,单例模式(Singleton Pattern) 是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式常用于管理全局资源、配置或共享状态,避免重复创建对象带来的开销或冲突。

1. 单例模式的核心思想

(1) 核心特性

  • 唯一实例:整个程序中只能有一个该类的对象。
  • 全局访问:通过静态方法(如 getInstance())获取唯一实例。
  • 延迟初始化(Lazy Initialization):实例在第一次使用时才创建(可选)。
  • 禁止拷贝和赋值:防止通过拷贝或赋值创建新实例。

(2) 适用场景

  • 全局配置管理(如 MediaConfig、日志系统)。
  • 共享资源访问(如数据库连接池、线程池)。
  • 硬件设备控制(如打印机、传感器)。
  • 缓存系统(避免重复计算或加载数据)。

2. 单例模式的 C++ 实现

(1) 经典实现(C++98/03 风格)

#include <mutex>

class Singleton {
private:
    static Singleton* instance;  // 静态成员变量存储唯一实例
    static std::mutex mtx;      // 互斥锁(线程安全)

    // 私有构造函数,防止外部 new
    Singleton() {}

    // 禁止拷贝构造和赋值
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 获取唯一实例(线程安全)
    static Singleton* getInstance() {
        if (instance == nullptr) {  // 双重检查锁定(DCLP)
            std::lock_guard<std::mutex> lock(mtx);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    // 其他业务方法...
    void doSomething() {
        // ...
    }
};

// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

问题:

  • 内存泄漏:new Singleton() 未释放,需手动管理。
  • 双重检查锁定(DCLP) 在 C++98/03 中可能因指令重排序导致问题(C++11 后修复)。

(2) C++11 推荐实现(线程安全 + 无内存泄漏)

方法 1:局部静态变量(Meyer's Singleton)

class Singleton {
private:
    Singleton() {}  // 私有构造函数

    // 禁止拷贝构造和赋值
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    // 获取唯一实例(C++11 保证线程安全)
    static Singleton& getInstance() {
        static Singleton instance;  // 局部静态变量,线程安全
        return instance;
    }

    void doSomething() {
        // ...
    }
};

优点:

  • 线程安全:C++11 保证局部静态变量的初始化是线程安全的。
  • 懒加载:实例在第一次调用 getInstance() 时创建。
  • 无内存泄漏:程序退出时自动销毁静态变量。

方法 2:智能指针(std::unique_ptr

#include <memory>
#include <mutex>

class Singleton {
private:
    static std::unique_ptr<Singleton> instance;
    static std::mutex mtx;

    Singleton() {}

    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

public:
    static Singleton* getInstance() {
        if (!instance) {
            std::lock_guard<std::mutex> lock(mtx);
            if (!instance) {
                instance = std::make_unique<Singleton>();
            }
        }
        return instance.get();
    }
};

// 初始化静态成员
std::unique_ptr<Singleton> Singleton::instance = nullptr;
std::mutex Singleton::mtx;

适用场景:

  • 需要显式控制实例生命周期(如提前销毁)。

3. 单例模式的优缺点

(1) 优点

控制实例数量    确保全局唯一,避免资源浪费
线程安全    C++11 后局部静态变量实现简单且安全
延迟初始化    按需创建,节省启动时间
封装性好    比全局变量更安全,可控制访问权限

 

(2) 缺点

难以测试    单例的静态依赖可能导致单元测试困难
滥用风险    过度使用单例可能导致代码耦合度高
内存泄漏风险    经典实现需手动释放内存(C++11 局部静态变量无此问题)
多线程问题    C++98/03 的双重检查锁定可能有隐患

 

demo:

class Logger {
private:
    Logger() {}  // 私有构造函数

public:
    static Logger& getInstance() {
        static Logger logger;  // 线程安全 + 懒加载
        return logger;
    }

    void log(const std::string& message) {
        // 记录日志...
    }
};

// 使用
Logger::getInstance().log("Hello, Singleton!");

 

posted @ 2025-08-26 20:33  一个不知道干嘛的小萌新  阅读(127)  评论(0)    收藏  举报