特殊类设计[下] --- 单例模式

文章目录

  • 5.只能创建一个对象的类
    • 5.1设计模式[2.5 万字详解:23 种设计模式](https://zhuanlan.zhihu.com/p/433152245)
    • 5.2单例模式
      • 1.饿汉模式
      • 1.懒汉模式
  • 6.饿汉模式
  • 7.懒汉模式
    • 7.1饿汉模式优缺点:
    • 7.2懒汉模式
      • 1.线程安全问题
      • 2.单例对象的析构问题
  • 8.整体代码
  • 9.C++11后可用的单例模式

5.只能创建一个对象的类

5.1设计模式2.5 万字详解:23 种设计模式

在这里插入图片描述

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结

为什么会产生设计模式这样的东西呢?

就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。春秋战国时期,七国之间经常打仗,发现打仗也是有套路的,孙子就总结出了《孙子兵法》

使用设计模式的目的是什么呢?

代码可重用性、代码更容易被理解、代码可靠性、代码编写工程化

设计模式是软件工程的基石脉络,如同大厦的结构一样

5.2单例模式

在这里插入图片描述

一个类只能创建一个对象,即单例模式

该模式可以保证系统中(一个进程)该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。[在此进程全局只有唯一一个 且 在任意地方可访问]

应用场景

在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,服务进程中的其他对象通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理

1.饿汉模式

1.懒汉模式

6.饿汉模式

程序启动时(main函数之前)就创建一个唯一的实例对象

class Singleton
{
public:static Singleton* GetPtrAtOnly(){return _ponly;}void PushData(const string& str){_mtx.lock();_vec.push_back(str);_mtx.unlock();}void Display(){_mtx.lock();for (auto& e : _vec){cout << e << endl;}cout << endl;_mtx.unlock();}private://构造函数私有化 -- 禁止类外创建对象Singleton(){}private:mutex _mtx;vector<string> _vec;//_ponly是一个存在于静态区的指针变量//这个指针初始化指向 一个Singleton对象static Singleton* _ponly;
};//在程序入口之前就完成单例对象的初始化
//类内声明 类外初始化
Singleton* Singleton::_ponly = new Singleton;int main()
{//Singleton s1;//static Singleton s2;//Singleton* p = new Singleton;Singleton::GetPtrAtOnly()->PushData("彭于晏");Singleton::GetPtrAtOnly()->PushData("吴彦祖");Singleton::GetPtrAtOnly()->PushData("黎明");Singleton::GetPtrAtOnly()->PushData("郭富城");Singleton::GetPtrAtOnly()->Display();return 0;
}

在这里插入图片描述
在这里插入图片描述

多线程单例模式之饿汉模式测试

int main()
{srand(time(0));int n = 10;thread t1([n](){for (size_t i = 0; i < n; ++i){Singleton::GetPtrAtOnly()->PushData("线程1: " + to_string(rand()));}});thread t2([n](){for (size_t i = 0; i < n; ++i){Singleton::GetPtrAtOnly()->PushData("线程2: " + to_string(rand()));}});t1.join();t2.join();Singleton::GetPtrAtOnly()->Display();return 0;
}

在这里插入图片描述

7.懒汉模式

7.1饿汉模式优缺点:

优点:相对懒汉模式而言简单一些
缺点:

  1. 影响进程启动速度
    饿汉模式main函数之前就要创建对象
    若单例对象初始化很慢(初始化操作很多[读取配置文件]) 对象1暂时不占用资源
    但是会影响后续程序的启动速度
  2. 多个单例类对象 实例启动顺序不确定
    两个有依赖关系的单例都是饿汉时
    若要求创建顺序:单例1--单例2
    饿汉模式无法控制顺序

7.2懒汉模式

1.线程安全问题

  1. 懒汉模式
static Singleton* GetPtrAtOnly()
{if (_ponly == nullptr){if (_ponly == nullptr){_ponly = new Singleton;}}return _ponly;
}

假设两个线程 线程1的对象实例化后进行了添加数据 此时线程2执行 覆盖线程1

  1. 饿汉模式不用考虑

线程在main函数后进行 饿汉模式在main函数前就创建了对象

    static Singleton* GetPtrAtOnly(){return _ponly;}Singleton* Singleton::_ponly = new Singleton;

加锁保护

	static Singleton* GetPtrAtOnly(){_imtx.lock();if (_ponly == nullptr){_ponly = new Singleton;}_imtx.unlock();return _ponly;}

每次创建对象都要 加锁解锁 有无改进办法?

	static Singleton* GetPtrAtOnly(){if (_ponly == nullptr){_imtx.lock();_ponly = new Singleton;_imtx.unlock();}return _ponly;}

此时相当于没加锁 跟没加锁造成的问题一样 以下的双检查加锁才是解决办法

	static Singleton* GetPtrAtOnly(){//懒汉模式 不在外部加锁 提高效率 -- 要不然每次创建对象都要加锁if (_ponly == nullptr){_imtx.lock();//线程安全 t1判断为空 new对象 t2来了不为空 不再new 更正了覆盖问问题if (_ponly == nullptr){_ponly = new Singleton;}_imtx.unlock();}return _ponly;}

2.单例对象的析构问题

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

8.整体代码

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <array>
#include <time.h>
#include <queue>
#include <stack>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map> 
#include <thread> 
#include <functional>
#include <assert.h>
#include<mutex>
using namespace std;// 饿汉模式:
/*
class Singleton
{
public:static Singleton* GetPtrAtOnly(){return _ponly;}void PushData(const string& str){_mtx.lock();_vec.push_back(str);_mtx.unlock();}void Display(){_mtx.lock();for (auto& e : _vec){cout << e << endl;}cout << endl;_mtx.unlock();}private://构造函数私有化 -- 禁止类外创建对象Singleton(){}private:mutex _mtx;vector<string> _vec;//_ponly是一个存在于静态区的指针变量//这个指针初始化指向 一个Singleton对象//这里可以直接static Singleton _only; 他是一个对象 程序结束时调用析构//而懒汉模式只能是指针因为他要判断是否空再去创建对象//所以懒汉模式不得不写一个对象回收实现自动析构static Singleton* _ponly;
};
Singleton* Singleton::_ponly = new Singleton;
*///懒汉模式:第一次访问实例对象时[第一次调用GetPtrAtOnly()]创建
class Singleton
{
public://获取单例对象static Singleton* GetPtrAtOnly(){if (_ponly == nullptr){_ptrmtx.lock();if (_ponly == nullptr){_ponly = new Singleton;}_ptrmtx.unlock();}return _ponly;}// 一般全局都要使用单例对象 // 所以单例对象一般不需要显示释放  // 特殊场景 -- 显示释放//释放单例对象static void DeletePtrAtOnly(){_ptrmtx.lock();if (_ponly != nullptr){delete _ponly;_ponly = nullptr;}_ptrmtx.unlock();}void PushData(const string& str){_vecmtx.lock();_vec.push_back(str);_vecmtx.unlock();}void Display(){_vecmtx.lock();for (auto& e : _vec){cout << e << endl;}cout << endl;_vecmtx.unlock();}~Singleton(){// 要求程序结束时// 将数据写到文件 // 单例对象析构时[持久化]// 即析构前做事情 // 写文件操作//DeletePtrAtOnly();//存在一种情况 写文件操作代码量太大 最后忘记调用DeletePtrAtOnly();//此时有没有析构单例对象 怎么办? 能不能搞得智能一点?//类比智能指针 再搞一个类 使得实现"自动化"//_gc是一个静态局部变量 他的析构发生在main函数结束后 程序结束时//_gc析构时 会调用他的析构函数~Garbage_Collection(); //他的析构时会调用单例对象的析构函数 由此实现自动化}// 单例对象回收class Garbage_Collection{public:~Garbage_Collection(){DeletePtrAtOnly();}};static Garbage_Collection _gc;private:Singleton(){}//有锁时 不禁用拷贝构造也行 因为锁使得vector不能push_backSingleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;
private:mutex _vecmtx;vector<string> _vec;static mutex _ptrmtx;static Singleton* _ponly;
};mutex Singleton::_ptrmtx;Singleton* Singleton::_ponly = nullptr;Singleton::Garbage_Collection Singleton::_gc;int main()
{//Singleton s(*Singleton::GetPtrAtOnly());srand(time(0));int n = 20;thread t1([n](){for (size_t i = 0; i < n; ++i){Singleton::GetPtrAtOnly()->PushData("线程1: " + to_string(rand()));}});thread t2([n](){for (size_t i = 0; i < n; ++i){Singleton::GetPtrAtOnly()->PushData("线程2: " + to_string(rand()));}});t1.join();t2.join();Singleton::GetPtrAtOnly()->Display();return 0;
}

9.C++11后可用的单例模式

C++11单例模式简单写法:将对象定义GetPtrAtOnly()函数的局部静态变量 返回对象的引用 在GetPtrAtOnly()函数首次调用时完成静态对象初始化
当某一个线程调用GetPtrAtOnly()执行初始化静态变量时,若其他线程正在执行初始化该静态变量 则先初始化上一进程

class Singleton
{
public:// C++11后才可以保证初始化静态对象的线程安全问题static Singleton* GetPtrAtOnly(){static Singleton one; return &one;}void PushData(const string& str){_vecmtx.lock();_vec.push_back(str);_vecmtx.unlock();}void Display(){_vecmtx.lock();for (auto& e : _vec){cout << e << endl;}cout << endl;_vecmtx.unlock();}~Singleton(){}
private:Singleton(){}Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;mutex _vecmtx;vector<string> _vec;
};

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

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

相关文章

react-组件间的通讯

一、父传子 父组件在使用子组件时&#xff0c;提供要传递的数据子组件通过props接收数据 class Parent extends React.Component {render() {return (<div><div>我是父组件</div><Child name"张" age{16} /></div>)} }const Child …

【洛谷 P3654】First Step (ファーストステップ) 题解(模拟+循环枚举)

First Step (ファーストステップ) 题目背景 知らないことばかりなにもかもが&#xff08;どうしたらいいの&#xff1f;&#xff09; 一切的一切 尽是充满了未知数&#xff08;该如何是好&#xff09; それでも期待で足が軽いよ&#xff08;ジャンプだ&#xff01;&#xff09…

华为---DHCP中继代理简介及示例配置

DHCP中继代理简介 IP动态获取过程中&#xff0c;客户端&#xff08;DHCP Client&#xff09;总是以广播&#xff08;广播帧及广播IP报文&#xff09;方式来发送DHCPDISCOVER和DHCPREQUEST消息的。如果服务器&#xff08;DHCP Server&#xff09;和 客户端不在同一个二层网络(二…

人工智能:CNN(卷积神经网络)、RNN(循环神经网络)、DNN(深度神经网络)的知识梳理

卷积神经网络&#xff08;CNN&#xff09; 卷积神经网络&#xff08;CNN&#xff09;&#xff0c;也被称为ConvNets或Convolutional Neural Networks&#xff0c;是一种深度学习神经网络架构&#xff0c;主要用于处理和分析具有网格状结构的数据&#xff0c;特别是图像和视频数…

VSCode 开发 Vue 语法提示

一. 打开应用商店&#xff0c;搜索 vetur &#xff0c;选择第一个&#xff0c;点击安装。 二. 安装完成后&#xff0c;还可以下载 Vue Language Features 解决代码警告的问题。 最后重启 VSCode 就可以使用啦。另外输入 按回车键还可以自动生成 vue 代码格式哦。 原创作者&…

原生mysql与mybatis执行update语句的差异

在做一个解除绑定的接口中&#xff0c;发现了这个一个问题&#xff1a; 连续对接口进行测试&#xff0c;发现一直fan返回解除成功&#xff0c;但是逻辑上应该是解除之后&#xff0c;在解除它后就应该回显已解除绑定才对 就一直找原因&#xff0c;sql中使用的是mybatis的…

【Qt之QtConcurrent】描述及使用

描述 QtConcurrent是一个Qt库中的模块&#xff0c;用于实现多线程并发编程。它提供了一些高级API&#xff0c;使得在多核处理器上并行执行代码变得更加容易。 示例&#xff1a; 使用的话&#xff0c; 需要在pro文件中添加&#xff1a;QT concurrent模块。 #include <QC…

基于机器视觉的车道线检测 计算机竞赛

文章目录 1 前言2 先上成果3 车道线4 问题抽象(建立模型)5 帧掩码(Frame Mask)6 车道检测的图像预处理7 图像阈值化8 霍夫线变换9 实现车道检测9.1 帧掩码创建9.2 图像预处理9.2.1 图像阈值化9.2.2 霍夫线变换 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分…

Virtual DOM

目录 Virtual DOM 前言 用法 代码 理解 Virtual DOM的工作原理&#xff1a; 为什么使用Virtual DOM? 哪些库/框架使用Virtual DOM? 总结 Virtual DOM&#xff08;虚拟DOM&#xff09;是一种编程概念&#xff0c;它是对真实DOM的轻量级抽象表示。在前端开发中&#x…

RHCE8 资料整理(四)

RHCE8 资料整理 第四篇 存储管理第13章 硬盘管理13.1 对磁盘进行分区13.2 交换分区&#xff08;swap分区&#xff09; 第14章 文件系统14.1 了解文件系统14.2 了解硬链接14.3 创建文件系统14.4 挂载文件系统14.5 设置永久挂载14.6 查找文件14.7 find的用法 第15章 逻辑卷管理15…

Go基础——数组、切片、集合

目录 1、数组2、切片3、集合4、范围&#xff08;range&#xff09; 1、数组 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列&#xff0c;这种类型可以是任意的原始类型例如整型、字符串或者自定义类型。 Go 语言数组声明需要指定元素类型及元素个数&#xff0c;与…

基于图像识别的跌倒检测算法 计算机竞赛

前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于图像识别的跌倒检测算法 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/…

GO语言代码示例

首先&#xff0c;我们需要安装 rod 库&#xff0c;这是一个用于构建网络爬虫的 Go 语言库。 使用 go get 命令安装 rod 库&#xff1a;go get -u github.com/gofiber/rod 创建一个新的 Go 程序文件&#xff0c;例如&#xff1a;main.go 在 main.go 文件中&#xff0c;导入 r…

c++系列之vector类模拟实现

&#x1f497; &#x1f497; 博客:小怡同学 &#x1f497; &#x1f497; 个人简介:编程小萌新 &#x1f497; &#x1f497; 如果博客对大家有用的话&#xff0c;请点赞关注再收藏 &#x1f31e; 构造函数 vector() //_begin表示有效成员的开始 //_finish表示有效成员的大小…

配置Sentinel 控制台

1.遇到的问题 服务网关 | RuoYi 最近调试若依的微服务版本需要用到Sentinel这个组件&#xff0c;若依内部继承了这个组件连上即用。 Sentinel是阿里巴巴开源的限流器熔断器&#xff0c;并且带有可视化操作界面。 在日常开发中&#xff0c;限流功能时常被使用&#xff0c;用…

力扣:142. 环形链表 II(Python3)

题目&#xff1a; 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评…

第13期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

k8s 金丝雀发布与声明式管理

Deployment控制器支持自定义控制更新过程中的滚动节奏&#xff0c;如“暂停(pause)”或“继续(resume)”更新操作。比如等待第一批新的Pod资源创建完成后立即暂停更新过程&#xff0c;此时&#xff0c;仅存在一部分新版本的应用&#xff0c;主体部分还是旧的版本。然后&#xf…

Vue+el-image-viewer显示tiff图片,并能够切换图片中的帧

一、简述 在前端界面显示tiff图片&#xff0c;并能够点击翻页按钮切换tiff图片中的帧&#xff0c;接收到后端传来的buffer&#xff0c;在前端处理后进行展示 二、使用工具 引入Tiff.js文件&#xff0c;引入前先进行下载安装 import Tiff from tiff.js引入显示图片组件 comp…

【牛牛送书 | 第二期】《ChatGPT 驱动软件开发:AI 在软件研发全流程中的革新与实践》

目录 前言&#xff1a; 本书目录&#xff1a; 内容简介&#xff1a; 专家评价&#xff1a; 适合对象&#xff1a; 送书规则&#xff1a; 前言&#xff1a; 现如今&#xff0c;随着计算机技术的不断发展和互联网的普及&#xff0c;我们已经迈入了一个高效的信息处理和传…