C++ 单例模式

懒汉模式

  1. 在多线程情况下,懒汉模式是线程是不安全的,如果多个线程同时去访问单例对象,而这个单例对象尚未初始化,那么在判断 instance == nullptr 的时候,可能会出现 instance 已经在创建了,但是判断结果还是为true,就会创建出多个单例对象的实例;

解决方案:使用双检查锁;使用静态局部变量也可以解决;

为什么要两次判断 instance == nullptr 之后,才初始化单例对象?

假设此时单例对象还没有创建,有两个线程同时进入单例对象的访问函数,此时两个线程都通过的第一次为空的判断,在两次判断之间有一把互斥锁,只有一个线程可以获取,该线程获取后,第二次判断为空,开始初始化单例对象,初始化结束后释放锁;此时另一个线程进入第二次为空判断,发现单例对象已经初始化;通过双检查锁的机制,可以避免线程安全问题;

为什么互斥锁在两次检查之间获取,而不是在第一次检查开始前直接获取?

如果放在第一次检查前,那么每次获取单例对象,都要先获取互斥锁,会带来极大的资源浪费;

  1. 单例模式的默认构造函数需要设置为private,且拷贝构造函数和 "=" 赋值运算符都要禁用;

单例模式的默认构造函数设置为private是为了防止构造函数被外部调用,如果外部可以调用单例类的构造函数,那么这就不会仅存在一个单例;

禁用拷贝构造函数和 "=" 赋值运算符也是同理,反之单例类对象被多次创建;

cpp 复制代码
// 线程安全的懒汉模式
#include <mutex>

class SingleClass {

public:
    SingleClass(const SingleClass&) = delete;
    SingleClass& operator=(const SingleClass&) = delete;

    static SingleClass *getInstance() {
        if (instance == nullptr) {
            m_mutex.lock();
            if (instance == nullptr) {
                instance = new SingleClass();
            }
            m_mutex.unlock();
        }
        return instance;
    }

private:
    static SingleClass *instance;
    static std::mutex m_mutex;

    SingleClass() = default;
    
};

// 静态变量需要在类内声明,在类外初始化
SingleClass *SingleClass::instance = nullptr;
std::mutex SingleClass::m_mutex;

饿汉模式

  1. 与懒汉模式的区别就在于,在程序启动时,或在类加载时编译期,就将单例类实例化,所以不需要双检查锁,也就不存在线程安全问题;在获取单例实例的时候,直接return instance 即可。
相关推荐
2401_8920709816 小时前
【Linux C++ 日志系统实战】LogFile 日志文件管理核心:滚动策略、线程安全与方法全解析
linux·c++·日志系统·日志滚动
yuzhuanhei16 小时前
Visual Studio 配置C++opencv
c++·学习·visual studio
不爱吃炸鸡柳17 小时前
C++ STL list 超详细解析:从接口使用到模拟实现
开发语言·c++·list
十五年专注C++开发17 小时前
RTTR: 一款MIT 协议开源的 C++ 运行时反射库
开发语言·c++·反射
Momentary_SixthSense17 小时前
设计模式之工厂模式
java·开发语言·设计模式
Java码农也是农17 小时前
Multi-Agent 系统设计模式
设计模式·agent·multi-agent
sg_knight17 小时前
设计模式实战:状态模式(State)
python·ui·设计模式·状态模式·state
‎ദ്ദിᵔ.˛.ᵔ₎17 小时前
STL 栈 队列
开发语言·c++
2401_8920709818 小时前
【Linux C++ 日志系统实战】高性能文件写入 AppendFile 核心方法解析
linux·c++·日志系统·文件写对象
郭涤生18 小时前
STL vector 扩容机制与自定义内存分配器设计分析
c++·算法