C++单例模式

定义

  1. 类的实例只有一个

特点

  1. 构造函数私有化,在类内部只调用一次
  2. 拷贝构造函数私有化或者禁用

饿汉单例

  1. 类加载的时候立刻进行实例化
    1. 定义这个单例类的时候,就把这个静态的单例对象创建出来了

example

cpp 复制代码
// 饿汉模式
class TaskQueue
{
public:
    // = delete 代表函数禁用, 也可以将其访问权限设置为私有
    TaskQueue(const TaskQueue& obj) = delete;
    TaskQueue& operator=(const TaskQueue& obj) = delete;
    static TaskQueue* getInstance()
    {
        return m_taskQ;
    }
private:
    TaskQueue() = default;
    static TaskQueue* m_taskQ;
};
// 静态成员初始化放到类外部处理
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;

int main()
{
    TaskQueue* obj = TaskQueue::getInstance();
}

懒汉单例

  1. 类加载的时候不去创建这个唯一的实例,而是在需要使用的时候再进行实例化

example

cpp 复制代码
// 懒汉模式
class TaskQueue
{
public:
    // = delete 代表函数禁用, 也可以将其访问权限设置为私有
    TaskQueue(const TaskQueue& obj) = delete;
    TaskQueue& operator=(const TaskQueue& obj) = delete;
    static TaskQueue* getInstance()
    {
        if(m_taskQ == nullptr)
        {
            m_taskQ = new TaskQueue;
        }
        return m_taskQ;
    }
private:
    TaskQueue() = default;
    static TaskQueue* m_taskQ;
};
TaskQueue* TaskQueue::m_taskQ = nullptr;

缺点

  1. 多线程环境下,可能生成多个单例
    1. 在调用getInstance()函数获取单例对象的时候,如果在单线程情况下是没有什么问题的,如果是多个线程,调用这个函数去访问单例对象就有问题了。假设有三个线程同时执行了getInstance()函数,在这个函数内部每个线程都会new出一个实例对象。此时,这个任务队列类的实例对象不是一个而是3个,很显然这与单例模式的定义是相悖的

解决方案

  1. 加锁
  2. 局部静态变量
cpp 复制代码
class TaskQueue
{
public:
    // = delete 代表函数禁用, 也可以将其访问权限设置为私有
    TaskQueue(const TaskQueue& obj) = delete;
    TaskQueue& operator=(const TaskQueue& obj) = delete;
    static TaskQueue* getInstance()
    {
        static TaskQueue taskQ;
        return &taskQ;
    }
    void print()
    {
        cout << "hello, world!!!" << endl;
    }

private:
    TaskQueue() = default;
};

int main()
{
    TaskQueue* queue = TaskQueue::getInstance();
    queue->print();
    return 0;
}

在程序的第 9、10 行定义了一个静态局部队列对象,并且将这个对象作为了唯一的单例实例。使用这种方式之所以是线程安全的,是因为在C++11标准中有如下规定,并且这个操作是在编译时由编译器保证的:

如果指令逻辑进入一个未被初始化的声明变量,所有并发执行应当等待该变量完成初始化。

PS:局部静态变量

  1. 在函数内部进行初始化,且只在第一次进入函数时执行初始化操作。初始化方式和普通局部变量类似,只是因为它是静态的,后续函数调用时不会再次初始化。

example

相关推荐
昙鱼4 分钟前
Maven的了解与使用
java·maven
北纬39°的风18 分钟前
从0开始搭建一个生产级SpringBoot2.0.X项目(十)SpringBoot 集成RabbitMQ
java·spring boot·redis
forestqq29 分钟前
设置JAVA以适配华为2288HV2服务器的KVM控制台
java·运维·服务器
LUwantAC31 分钟前
Java学习路线:Maven(一)认识Maven
java·学习·maven
勤匠1 小时前
使用 Stream 处理集合数据【Java 1.8 新特性】
java
攻城狮7号1 小时前
【5.5】指针算法-三指针解决颜色分类
c++·算法
OKkankan1 小时前
单链表的实现(数据结构)
java·c语言·数据结构·c++
威哥爱编程1 小时前
适合才最美:Shiro安全框架使用心得
java·shiro·javaee
gkdpjj1 小时前
二叉树中的深搜
c++·算法
Lyqfor1 小时前
Redis学习:BitMap/HyperLogLog/GEO案例 、布隆过滤器BloomFilter、缓存预热+缓存雪崩+缓存击穿+缓存穿透
java·数据库·redis·学习·算法·缓存·1024程序员节