C++单例设计模式

C++单例设计模式

文章目录

  • C++单例设计模式
    • 单例设计模式介绍
      • 饿汉式单例设计模式
      • 懒汉式单例设计模式
      • 什么是可重入函数

单例设计模式介绍

单例模式指的是,无论怎么获取,永远只能得到该类类型的唯一一个实例对象,那么设计一个单例就必须要满足下面三个条件:

  1. 构造函数私有化,这样用户就不能任意定义该类型的对象了
  2. 定义该类型唯一的对象
  3. 通过一个static静态成员方法返回唯一的对象实例

在写单例设计模式的时候,我们就可以采用这样的步骤来写单例模式

饿汉式单例设计模式

#include <iostream>//饿汉式单例设计模式
class Single
{
public://3. 获取类的唯一实例对象的接口方法static Single* getInstacne() { return &instance; }void printSingle(){std::cout << "hello codechen" << char(10);}
private://2. 定义一个唯一的类的实例化的对象static Single instance;//1. 构造函数的私有化,不能够自己主动的去调用构造函数Single(){//在实际的项目中,构造函数可能会需要做很多的工作//比如说对一些成员变量的初始化,对一些数据的读取等等}Single(const Single&) = delete;Single& operator = (const Single&) = delete;
};
Single Single::instance{};int main()
{Single* ptr1 = Single::getInstacne();ptr1->printSingle();delete ptr1;return 0;
}

懒汉式单例设计模式

#include <iostream>//懒汉式单例设计模式
class Single
{
public://3. 获取类的唯一实例对象的接口方法static Single* getInstacne() { std::cout << "hello codechen,你成功的调用了一次构造函数" << char(10);if (instance == nullptr){std::cout << "在这里对instance进行了初始化" << char(10);instance = new Single();}return instance;}
private://2. 定义一个唯一的类的实例化的对象,为指针static Single* instance;//1. 构造函数的私有化,不能够自己主动的去调用构造函数Single(){//在实际的项目中,构造函数可能会需要做很多的工作//比如说对一些成员变量的初始化,对一些数据的读取等等}Single(const Single&) = delete;Single& operator = (const Single&) = delete;
};
Single* Single::instance = nullptr;int main()
{Single* ptr1 = Single::getInstacne();Single* ptr2 = Single::getInstacne();Single* ptr3 = Single::getInstacne();delete ptr1;delete ptr2;delete ptr3;return 0;
}

什么是可重入函数

下面讲到线程安全问题,先引入一个可重入函数的概念

可重入函数是指在程序中可以被多个任务安全地调用的函数。这类函数在执行过程中不会修改全局变量,而是使用局部变量和线程特定数据等机制来保存数据。可重入函数在收到信号后不会导致数据出错,因此可以在信号处理函数中使用。与之相反,不可重入函数在收到信号后可能会修改全局变量,从而导致程序出现不可预料的后果。

在Linux系统编程中,为了提高程序的稳定性,应尽量使用可重入函数进行信号处理。同时,避免在信号处理函数中使用不可重入函数,以降低信号处理函数的复杂性。

可重入函数的特点:

  1. 使用局部变量而非全局变量。
  2. 避免使用静态数据结构。
  3. 不调用malloc()或free()等内存分配函数。
  4. 使用线程特定数据(如pthread_key_t)保存数据,以实现多线程间的数据隔离。

总之,可重入函数是在多任务、多线程环境下保证程序稳定性的重要手段。

为什么懒汉模式可能会涉及到线程安全的问题

	static Single* getInstacne() { std::cout << "hello codechen,你成功的调用了一次构造函数" << char(10);if (instance == nullptr){//在这里我们进行多种的操作,比如说开闭内存,构造对象和给Single赋值等std::cout << "在这里对instance进行了初始化" << char(10);instance = new Single();}return instance;}

我们看到这个函数,在if的判断语句中,在这里我们进行多种的操作,比如说开闭内存,构造对象和给Single赋值等。

如果一个线程,比如线程A进来了,看到这个instance == nullptr,会对她进行操作,这个时候如果线程B也进来了,这个线程A还没有对instance 赋值的话,这个线程B也是认为这个instance是没有赋值的,所以她也是会进入到去执行if内的语句。

如何解决这个问题

在这里我们最好的解决方式就是锁加上双重判断的方式

我们为什么要双重判断?

比如我线程A进来了,A拿到了锁,但是这个时候没有对instance赋值,线程B也是可以进来的,但是拿不到锁会阻塞在那个地方,如果线程A结束了,线程B还是会去执行if里面的语句,所以这里还要再加上一个if的双重判断。

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
std::mutex mylock;
//线程安全的,懒汉式单例设计模式
class Single
{
public://3. 获取类的唯一实例对象的接口方法//锁加上双重判断static Single* getInstacne() { std::cout << "hello codechen,你成功的调用了一次构造函数" << char(10);if (instance == nullptr){lock_guard<std::mutex> guard(mylock);if (instance == nullptr){//在这里我们进行多种的操作,比如说开闭内存,构造对象和给Single赋值等std::cout << "在这里对instance进行了初始化" << char(10);instance = new Single();}}return instance;}
private://2. 定义一个唯一的类的实例化的对象,为指针static Single* volatile instance;//1. 构造函数的私有化,不能够自己主动的去调用构造函数Single(){//在实际的项目中,构造函数可能会需要做很多的工作//比如说对一些成员变量的初始化,对一些数据的读取等等}Single(const Single&) = delete;Single& operator = (const Single&) = delete;
};
Single* Single::instance = nullptr;int main()
{Single* ptr1 = Single::getInstacne();Single* ptr2 = Single::getInstacne();Single* ptr3 = Single::getInstacne();delete ptr1;delete ptr2;delete ptr3;return 0;
}

关于volatile的作用

在这里插入图片描述

附加问题:

#include <iostream>
using namespace std;class CSingleton
{
public:static CSingleton* getInstance(){static CSingleton single; // 懒汉式单例模式,定义唯一的对象实例return &single;}
private:static CSingleton *single;CSingleton() { cout << "CSingleton()" << endl; }~CSingleton() { cout << "~CSingleton()" << endl;}CSingleton(const CSingleton&);
};
int main()
{CSingleton *p1 = CSingleton::getInstance();CSingleton *p2 = CSingleton::getInstance();CSingleton *p3 = CSingleton::getInstance();delete ptr1;delete ptr2;delete ptr3;return 0;
}

在这里插入图片描述

对于static静态局部变量的初始化,编译器会自动对它的初始化进行加锁和解锁控制,使静态局部变量的初始化成为线程安全的操作,不用担心多个线程都会初始化静态局部变量,因此上面的懒汉单例模式是线程安全的单例模式!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/307949.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GitHub Copilot 终极详细介绍

编写代码通常是一项乏味且耗时的任务。现代开发人员一直在寻找新的方法来提高编程的生产力、准确性和效率。 像 GitHub Copilot 这样的自动代码生成工具可以使这成为可能。 GitHub Copilot 到底是什么&#xff1f; GitHub Copilot 于 2021 年 10 月推出&#xff0c;是 GitHub 的…

pytorch机器学习各种激活函数总结(不完整学习更新中~)

pytorch各种激活函数总结 0.思维导图预览1. ReLU函数2. Sigmoid函数3. Softmax函数4. Tanh函数5.&#xff08;学习后更新&#xff09; 0.思维导图预览 1. ReLU函数 ReLU&#xff08;Rectified Linear Unit&#xff09;线性整流函数 其公式为&#xff1a; f ( x ) M a x ( 0 …

Python之自然语言处理库snowNLP

一、介绍 SnowNLP是一个python写的类库&#xff0c;可以方便的处理中文文本内容&#xff0c;是受到了TextBlob的启发而写的&#xff0c;由于现在大部分的自然语言处理库基本都是针对英文的&#xff0c;于是写了一个方便处理中文的类库&#xff0c;并且和TextBlob不同的是&…

昇腾910平台安装驱动、固件、CANN toolkit、pytorch

本文使用的昇腾910平台操作系统是openEuler&#xff0c;之前没了解过&#xff0c;不过暂时感觉用起来和centOS差不多。系统架构是ARM&#xff0c;安装包基本都是带aarch64字样&#xff0c;注意和x86_64区别开&#xff0c;别下错了。 安装依赖 cmake 通过yum安装的cmake版本较…

ES的使用(Elasticsearch)

ES的使用&#xff08;Elasticsearch&#xff09; es是什么&#xff1f; es是非关系型数据库&#xff0c;是分布式文档数据库&#xff0c;本质上是一个JSON 文本 为什么要用es? 搜索速度快&#xff0c;近乎是实时的存储、检索数据 怎么使用es? 1.下载es的包&#xff08;环境要…

Word 将页面方向更改为横向或纵向

文章目录 更改整个文档的方向更改部分页面的方向方法1&#xff1a;方法2&#xff1a; 参考链接 更改整个文档的方向 选择“布局”>“方向”&#xff0c;选择“纵向”或“横向”。 更改部分页面的方向 需要达到下图结果&#xff1a; 方法1&#xff1a; 选:中你要在横向页面…

新品出击 | 软网关BLIoTLink免费发布

新品出击|软网关BLIoTLink免费发布 BLIoTLink是一款免费的物联网协议转换软件&#xff0c;可以部署在任何基于Linux OS的系统&#xff08;Linux、Debian、Ubuntu、FreeRTOS、RT-Thread&#xff09;中&#xff0c;使用灵活&#xff0c;可以实现数据的采集以及接入网络平台。 BL…

Mybatis行为配置之Ⅳ—日志

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 再谈动态SQL Mybatis配置入门 Mybatis行为配置之Ⅰ—缓存 Mybatis行为配置…

Mac Pycharm在Debug模式报编码(SyntaxError)错误

1. 错误信息&#xff1a; Traceback (most recent call last):File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/lib/python3.9/tokenize.py", line 330, in find_cookieline_string line.decode(utf-8) UnicodeDeco…

鸿蒙HarmonyOS-图表应用

简介 随着移动应用的不断发展&#xff0c;数据可视化成为提高用户体验和数据交流的重要手段之一。在HarmonyOS应用开发中&#xff0c;一个强大而灵活的图表库是实现这一目标的关键。而MPChart就是这样一款图表库&#xff0c;它为开发者提供了丰富的功能和灵活性&#xff0c;使得…

Adobe 设计精髓:创新的用户体验 | 开源日报 No.130

adobe/react-spectrum Stars: 10.1k License: Apache-2.0 React Spectrum Libraries 是一系列的库和工具&#xff0c;旨在帮助开发者构建适应性强、可访问性好且稳健的用户体验。 核心优势&#xff1a; 提供全面的可访问性和行为支持&#xff0c;符合 WAI-ARIA 编写实践&…

小型内衣洗衣机什么牌子好?口碑好的小型洗衣机

想必大家都知道&#xff0c;我们的内衣裤、袜子这些衣物对卫生方面的要求是比较的高&#xff0c;毕竟是贴身的衣物&#xff0c;因此是要分开清洗的&#xff0c;而不能够跟我们其他的大件衣服一起放入到大型洗衣机里进行混洗&#xff0c;很多就选择了分开单独的手洗&#xff0c;…