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

文章目录

  • 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.mzph.cn/news/121248.shtml

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

相关文章

UVa129 Krypton Factor(困难的串)

1、题目 2、题意 如果一个字符串包含两个相邻的重复子串&#xff0c;则称它是“容易的串”&#xff0c;其他串称为“困难的串”。例如&#xff0c;BB、ABCDACABCAB、ABCDABCD都是容易的的串&#xff0c;而D、DC、ABDAB、CBABCBA 都是困难的串。 输入正整数 k k k 和 L L L&a…

K8S基础架构租赁(Lease )

分布式系统通常需要租约(leases)&#xff0c;租约提供了锁定共享资源和在一组成员之间协调活动的机制。 在Kubernetes中&#xff0c;租约的概念由协调(k8s.io) API组中的Lease对象表示。 在Kubernetes中&#xff0c;Lease对象用于协调集群中的节点和组件之间的通信和协作。例如…

Linux虚拟机部署与发布项目(Windows版本)

目录 前言 一、虚拟机部署项目的流程 二、单机项目 1. 本机测试 2.虚拟机部署项目 三、前后端分离项目 前言 在软件开发过程中&#xff0c;部署和发布项目是非常重要的一环。使用虚拟机技术可以方便、灵活且可重复使用地部署和发布项目。本篇博客将介绍如何在 Windows 环…

【密评】商用密码应用安全性评估从业人员考核题库(十四)

商用密码应用安全性评估从业人员考核题库&#xff08;十四&#xff09; 国密局给的参考题库5000道只是基础题&#xff0c;后续更新完5000还会继续更其他高质量题库&#xff0c;持续学习&#xff0c;共同进步。 3251 单项选择题 根据GB/T 39786《信息安全技术 信息系统密码应用…

Go基础——基础语法

1、简介 Go&#xff08;又称Golang&#xff09;是Google开发的一种静态强类型、编译型、并发型&#xff0c;并具有垃圾回收功能的编程语言。语法类似于C&#xff0c;专为高性能和并发程序而设计。通常用于网络编程、云服务器、游戏服务器、DevOps、Web应用、分布式系统、容器虚…

LeetCode--1991.找到数组的中间位置

1 题目描述 给你一个下标从 0 开始的整数数组 nums , 请你找到 最左边 的中间位置 middleIndex &#xff08;也就是所有可能中间位置下标最小的一个&#xff09; 中间位置 middleIndex 是满足 nums[0] nums[1] ... nums[middleIndex-1] nums[middleIndex1] nums[middleI…

【知识串联】概率论中的值和量(随机变量/数字特征/参数估计)【考研向】【按概率论学习章节总结】(最大似然估计量和最大似然估计值的区别)

就我的概率论学习经验来看&#xff0c;这两个概念极易混淆&#xff0c;并且极为重点&#xff0c;然而&#xff0c;在概率论的前几章学习中&#xff0c;如果只是计算&#xff0c;对这方面的辨析不清并没有问题。然而&#xff0c;到了后面的参数估计部分&#xff0c;却可能出现问…

mysql-linux归档版安装

什么是归档版安装&#xff1f;简单来说就是编译好的软件压缩打包版。 说明&#xff1a;我这里服务器之前已经装过一个不同版本的mysql&#xff0c;已经占用了3306端口&#xff0c;所以这里我用3307端口来演示&#xff0c;命令和官方的稍有不同&#xff0c;不过步骤都是差不多的…

搜索引擎搜索技巧总结

晚上在B站上刷到一个关于搜索技巧的干货视频&#xff0c;这个视频真的不错&#xff0c;结尾还提到了AI时代的搜索思路之前自己也零碎的探索出了一些搜索技巧&#xff0c;但是没有总结&#xff0c;就没法稳定的加入自己的工作流&#xff0c;持续提高效率受到这个视频的启发&…

计算机视觉 激光雷达结合无监督学习进行物体检测的工作原理

一、简述 激光雷达是目前正在改变世界的传感器。它集成在自动驾驶汽车、自主无人机、机器人、卫星、火箭等中。该传感器使用激光束了解世界,并测量激光击中目标返回所需的时间,输出是点云信息,利用这些信息,我们可以从3D点云中查找障碍物。 从自动驾驶汽车的角度看激光雷达…

mysql存在10亿条数据,如何高效随机返回N条纪录,sql如何写

1 低效方案 1.使用ORDER BY RAND()&#xff1a; SELECT * FROM your_table ORDER BY RAND() LIMIT 1; 这将随机排序表中的所有行&#xff0c;并且通过LIMIT 1仅返回第一行&#xff0c;从而返回一个随机记录。然而&#xff0c;对于大型表来说&#xff0c;ORDER BY RAND()可能会…

机器学习笔记:逆置换

1 介绍 给定一个排列 p&#xff0c;它的逆置换&#xff08;inverse permutation&#xff09;是一个排列 invp&#xff0c;满足 invp[p[i]] i 和 p[invp[i]] i 对所有 i 成立。 2 python实现 计算一个排列的逆排列给定一个排列 p&#xff0c;它的逆排列是一个排列 invp&…

PyTorch中的intrusive_ptr

PyTorch中的intrusive_ptr 前言 intrusive_ptr與unique_ptr&#xff0c;shared_ptr等一樣&#xff0c;都是smart pointer。但是intrusive_ptr比較特別&#xff0c;它所指向的物件類型必須繼承自intrusive_ptr_target&#xff0c;而intrusive_ptr_target必須實現引用計數相關的…

OpenCV 相机相关函数

一、变换参数矩阵的求解 1. 计算三个二维点对之间的仿射变换矩阵&#xff1a;getAffineTransform() 2. 计算多个二维点对之间的最优放射变换矩阵&#xff08;误差最小准则&#xff09;&#xff1a;estimateRigidTransform();或者findHomography(); 3. 计算四个二维点对之间的…

软考 系统架构设计师系列知识点之设计模式(7)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之设计模式&#xff08;6&#xff09; 所属章节&#xff1a; 老版&#xff08;第一版&#xff09;教材 第7章. 设计模式 第2节. 设计模式实例 相关试题 3. 某公司欲开发一套窗体图形界面类库。该类库需要包含若干预定…

针对多分类问题,使用深度学习--Keras进行微调提升性能

前面的文章对二分类问题用Keras进行了Fine-tune,使得模型的准确率进一步提升,此处对于多分类问题,尝试使用Fine-tune来提升性能。 1. 准备数据集 为了演示,本次选用了博文keras系列︱图像多分类训练与利用bottleneck features进行微调(三)中提到的数据集,原始的数据集…

专业135总分400+西安交通大学信息与通信工程学院909/815考研经验分享

今年初试发挥不错&#xff0c;400&#xff0c;专业课135&#xff0c;将近一年复习一路走来&#xff0c;感慨很多&#xff0c;希望以下经历可以给后来的同学提供一些参考。 初试备考经验 公共课&#xff1a;三门公共课&#xff0c;政治&#xff0c;英语&#xff0c;数学。在备考…

如何进行内存对齐和内存访问优化?

内存对齐和内存访问优化是C语言编程中的重要主题&#xff0c;对于提高程序性能和可移植性非常关键。在本文中&#xff0c;我们将深入探讨内存对齐和内存访问优化的概念、原理和实际应用。 什么是内存对齐&#xff1f; 内存对齐是一种指定数据在内存中存储位置的规则&#xff…

轮转数组(Java)

大家好我是苏麟 , 这篇文章是凑数的 ... 轮转数组 描述 : 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 题目 : 牛客 NC110 旋转数组: 这里牛客给出了数组长度我们直接用就可以了 . LeetCode 189.轮转数组 : 189. 轮…

Nginx 的配置文件(负载均衡,反向代理)

Nginx可以配置代理多台服务器&#xff0c;当一台服务器宕机之后&#xff0c;仍能保持系统可用。 cmd查找端口是否使用&#xff1a;netstat -ano Nginx出现403 forbidden #解决办法&#xff1a;修改web目录的读写权限&#xff0c;或者是把nginx的启动用户改成目录的所属用户&…