当前位置: 首页 > news >正文

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

文章目录

  • 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;
};

相关文章:

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

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

计算机网络-应用层(1)

一、DNS 域名系统 (DNS) 是把主机域名解析为IP地址的系统。该系统是由解析器和域名服务器组成的。采用UDP 协议&#xff0c;较少情况下使用TCP 协议&#xff0c;端口号均为53。 域名系统由三部分构成&#xff1a; DNS 名字空间、域名服务器、 DNS客户机。 (1)根域&#xff1a…...

Kotlin基础——枚举、When、in、for

枚举 声明只有值的枚举 enum class Color {RED, GREEN, BLUE }此外还可以增加属性和方法&#xff0c;如果需要在枚举类中定义方法&#xff0c;要使用分号把枚举常量列表和方法定义分开&#xff0c;这也是Kotlin唯一必须使用分号的地方 enum class Color(val r: Int, val g: …...

C++编程题目------平面上的最接近点对(分治算法)

题目描述 给定平面上n个点&#xff0c;找出其中的一对点的距离&#xff0c;使得在这n个点的所有点对中&#xff0c;该距离为所有点对中最小的。 输入格式 第一行一个整数 n&#xff0c;表示点的个数。 接下来 n 行&#xff0c;每行两个实数 x,y &#xff0c;表示一个点的行…...

Linux下的文件操作和文件管理

文章目录 应用编程文件操作文件描述符open函数write函数read函数close函数lseek函数文件操作例子 文件管理文件基本知识文件类型文件共享空洞文件错误处理退出程序原子操作fcntl和ioctl截断文件stat函数软链接和硬链接 应用编程 系统调用(system call)是Linux内核提供给应用层…...

设计模式之桥梁模式

什么是桥梁模式 桥梁模式&#xff08;Bridge Pattern&#xff09;也称为桥接模式&#xff0c;属于结构型模式&#xff0c;它主要目的是通过组合的方式建立两个类之间的联系&#xff0c;而不是继承。桥梁模式将抽象部分与它的具体实现部分分离&#xff0c;使它们都可以独立地变…...

“从部署到优化,打造高效会议管理系统“

目录 引言一、部署单机项目 - 会议OA1.1 硬件和软件环境准备1.2 检查项目1.3 系统部署1.后端部署 二、部署前后端分离项目 - SPA项目后端部署2.前端部署 总结 引言 在现代化办公环境中&#xff0c;会议是组织沟通、决策和合作的重要方式之一。为了提高会议的效率和质量&#x…...

Facebook广告效果数据获取

一、背景 公司每年在Facebook和Google上投放了大量的广告&#xff0c;我总不能让老板登录Facebook广告投放平台上去看广告效果&#xff0c;其实老板只关注每天花了多少钱引来了多少客户&#xff0c;每个客户平均花费多少钱&#xff0c;其它的他才不关心&#xff0c;有Facebook…...

nlp之文本转向量

文章目录 代码代码解读 代码 from tensorflow.keras.preprocessing.text import Tokenizer # 标记器(每一个词&#xff0c;以我们的数值做映射&#xff0c;)words [LaoWang has a Wechat account., He is not a nice person., Be careful.] # 把这句话中每一个单词&#xf…...

【luckfox】添加压力传感器hx711

文章目录 前言一、参考资料二、电路图三、驱动四、makefile——添加驱动五、dts——使能gpio5.1 参考5.2 改动1—— hx117节点5.3 改动2——引脚节点5.4 已经被定义的引脚5.5 gpio源码 六、改动总结——使能hx711七、验证驱动添加八、编写测试文件8.1 测试代码8.2 配置编译环境…...

C++11的lambda表达式

lambda来源于函数式编程的概念。C11这次终于把lambda加进来了。 lambda表达式有如下优点&#xff1a; 1、声明式编程风格&#xff1a;就地匿名定义目标函数或函数对象&#xff0c;不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序&#xff0c;好的可读性和可维护…...

矩阵特征值与特征向量的理解

各位朋友大家好&#xff0c;我是小C哈哈哈&#xff0c;很高兴认识大家&#xff0c;在这里&#xff0c;我会将一些枯燥难懂的数学和算法知识以图片或动画的形式通俗易懂的展现给大家&#xff0c;希望大家喜欢。 线性代数中的矩阵特征值与特征向量这两个基本概念总是让很多人摸不…...

云原生安全:如何保护云上应用不受攻击

文章目录 云原生安全的概念1. 多层次的安全性2. 自动化安全3. 容器安全4. 持续监控5. 合规性 云原生安全的关键挑战1. 无边界的环境2. 动态性3. 多云环境4. 容器化应用程序5. API和微服务 如何保护云上应用不受攻击1. 身份验证和访问控制示例代码&#xff1a; 2. 数据加密示例代…...

如何在用pip配置文件设置HTTP爬虫IP

首先&#xff0c;定义问题&#xff1a;在 Pip 中设置HTTP爬虫IP服务器&#xff0c;以便在网络上进行访问和下载。 亲身经验&#xff1a;我曾经遇到过类似问题&#xff0c;通过设置HTTP爬虫IP服务器成功解决了网络访问问题。 数据和引证&#xff1a;根据 pip 官方文档&#xff…...

2023MathorCup高校数模挑战赛B题完整解题代码教程

赛道 B&#xff1a; 电商零售商家需求预测及库存优化问题 问题背景&#xff1a; 电商平台存在着上千个商家&#xff0c;他们会将商品货物放在电商配套的仓库&#xff0c; 电商平台会对这些货物进行统一管理。通过科学的管理手段和智能决策&#xff0c; 大数据智能驱动的供应链…...

《动手学深度学习 Pytorch版》 10.7 Transformer

自注意力同时具有并行计算和最短的最大路径长度这两个优势。Transformer 模型完全基于注意力机制&#xff0c;没有任何卷积层或循环神经网络层。尽管 Transformer 最初是应用于在文本数据上的序列到序列学习&#xff0c;但现在已经推广到各种现代的深度学习中&#xff0c;例如语…...

ORACLE-递归查询、树操作

1. 数据准备 -- 测试数据准备 DROP TABLE untifa_test;CREATE TABLE untifa_test(child_id NUMBER(10) NOT NULL, --子idtitle VARCHAR2(50), --标题relation_type VARCHAR(10) --关系,parent_id NUMBER(10) --父id );insert into untifa_test (CHILD_ID, TITLE, RELATION_TYP…...

MySQL篇---第四篇

系列文章目录 文章目录 系列文章目录一、并发事务带来哪些问题?二、事务隔离级别有哪些?MySQL的默认隔离级别是?三、大表如何优化?一、并发事务带来哪些问题? 在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对 同一数据进行操作…...

em/px/rem/vh/vw单位的区别

一、绝对长度单位 1.px 表示像素&#xff0c;显示器上每个像素点大小都是相同的 二、相对长度单位 2.em 相对于当前对象内文本的字体尺寸&#xff0c;如未设置对行内文本字体的尺寸&#xff0c;则相对于浏览器的默认字体&#xff08;1em16px&#xff09; em值不是固定的&…...

【C++】多态 ③ ( “ 多态 “ 实现需要满足的三个条件 | “ 多态 “ 的应用场景 | “ 多态 “ 的思想 | “ 多态 “ 代码示例 )

文章目录 一、" 多态 " 实现条件1、" 多态 " 实现需要满足的三个条件2、" 多态 " 的应用场景3、" 多态 " 的思想 二、" 多态 " 代码示例 一、" 多态 " 实现条件 1、" 多态 " 实现需要满足的三个条件 &q…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)

漏洞概览 漏洞名称&#xff1a;Apache Flink REST API 任意文件读取漏洞CVE编号&#xff1a;CVE-2020-17519CVSS评分&#xff1a;7.5影响版本&#xff1a;Apache Flink 1.11.0、1.11.1、1.11.2修复版本&#xff1a;≥ 1.11.3 或 ≥ 1.12.0漏洞类型&#xff1a;路径遍历&#x…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent

安全大模型训练计划&#xff1a;基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标&#xff1a;为安全大模型创建高质量、去偏、符合伦理的训练数据集&#xff0c;涵盖安全相关任务&#xff08;如有害内容检测、隐私保护、道德推理等&#xff09;。 1.1 数据收集 描…...

手机平板能效生态设计指令EU 2023/1670标准解读

手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读&#xff0c;综合法规核心要求、最新修正及企业合规要点&#xff1a; 一、法规背景与目标 生效与强制时间 发布于2023年8月31日&#xff08;OJ公报&…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...