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

相关推荐
Mos_x1 天前
计算机组成原理核心知识点梳理
java·后端
墨寒博客栈1 天前
Linux基础常用命令
java·linux·运维·服务器·前端
回忆是昨天里的海1 天前
k8s-部署springboot容器化应用
java·容器·kubernetes
haofafa1 天前
STL之动态数组
开发语言·c++
INFINI Labs1 天前
使用 Docker Compose 轻松实现 INFINI Console 离线部署与持久化管理
java·docker·eureka·devops·docker compose·console·easyserach
Cosolar1 天前
国产麒麟系统 aarch64 架构 PostgreSQL 15 源码编译安装完整教程
java·后端
GalaxyPokemon1 天前
PlayerFeedback 插件开发日志
java·服务器·前端
无敌最俊朗@1 天前
梳理了音视频开发核心知识点
c++·音视频
天天摸鱼的java工程师1 天前
别再写那些重复代码了!8年Java老兵教你用 Hutool 提升开发效率
java·后端