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 即可。
相关推荐
拂拉氏几秒前
【项目分享-知识讲解】 C++标准库 list类的模拟实现
开发语言·c++·list·封装·stl标准库
刃神太酷啦3 分钟前
MySQL 库表操作 +数据类型+ 基础概念全梳理----《Hello MySQL!》(2)
java·c语言·数据库·c++·vscode·mysql·adb
zhengfei6118 小时前
第3章 Agent 类型分类与设计模式
设计模式
L_09078 小时前
【C++】异常
开发语言·c++
liulilittle9 小时前
关于拥塞控制的几点思考
网络·c++·tcp/ip·计算机网络·信息与通信·tcp·通信
刀法如飞9 小时前
一文搞懂DDD 领域驱动设计思想原理
设计模式·架构·代码规范
QT-Neal11 小时前
C++ 编码规范
c++
啦啦啦啦啦zzzz11 小时前
数据结构:红黑树理论
数据结构·c++·红黑树
Yolo_TvT11 小时前
C++:默认构造函数
c++