C++特殊类与单例模式

一、特殊类

类的特殊设计方式

①不能被拷贝的类

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝, 只需让该类不能调用拷贝构造函数以及赋值运算符重载即可

在C++98中,需要将拷贝构造设置成私有,并且只声明不定义,是因为该构造函数根本不会调用,定义了也并无意义

//不能被拷贝的类
//C++98
class CopyBan
{private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);
};//C++11
class CopyBan
{CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;
};

②只能在堆上创建对象的类

实现方法:

1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象

2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建

//只能在堆上创建对象的类
class HeapOnly
{
public:static HeapOnly* CreateObject(){return new HeapOnly;}
private:HeapOnly() {}HeapOnly(const HeapOnly&);//C++98HeapOnly(const HeapOnly&) = delete;//C++11
};

③只能在栈上创建对象的类

将构造函数私有化,然后设计静态方法创建对象返回

禁用operator new可以把下面用new 调用拷贝构造申请对象给禁止

//只能在栈上创建对象的类
class StackOnly
{
public:static StackOnly CreateObject(int x=0){return StackOnly(x);}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;StackOnly(StackOnly&& st)//拷贝构造被禁止之后,会导致创建StackOnly st1=StackOnly::CreateObj(1)失败,因此需要开放移动构造//但这样又会导致static StackOnly st2=move(st1)构造成功,因此并不能完全禁止:_x(st._x){}
private:StackOnly(int x=0):_x(x){}StackOnly(const StackOnly& st) = delete;//禁止静态对象拷贝private:int _x;
};

④不能被继承的类

//不能被继承的类
//C++98
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit() {}
};//C++11
class A final
{};

二、单例模式

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保障代码的可靠性

单例模式:一个类只能创建一个对象,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享

单例模式有两种实现模式:饿汉模式和懒汉模式

饿汉模式:

饿汉模式是指:不论未来是否使用,在main函数执行之前,就已经生成一个实例

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避 免资源竞争,提高响应速度更好

饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变。

#include<iostream>
#include<mutex>
#include<thread>
#include<vector>
#include<string>
#include<time.h>
using namespace std;//单例对象:只能创建一个对象的类//饿汉模式
//在main函数程序执行之前,就已经有了一个实例
class Singleton
{
public:static Singleton* GetInstance(){return _ins;}void Add(const string& str){_mtx.lock();_v.push_back(str);_mtx.unlock();}void Print(){_mtx.lock();for (auto& e : _v){cout << e << endl;}cout << endl;_mtx.unlock();}
private:Singleton() {};//限制类外随意创建对象//C++98防止拷贝//Singleton(Singleton const&);//Singleton& operator=(Singleton const&);//C++11防拷贝Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private:static Singleton* _ins;mutex _mtx;vector<string> _v;
};Singleton* Singleton::_ins=new Singleton;//在程序入口之前,就完成对单例对象的初始化int main()
{srand(time(0));int n = 30;thread t1([n]() {for (size_t i = 0; i < n; ++i){Singleton::GetInstance()->Add("t1线程:" + to_string(rand()));}});thread t2([n]() {for (size_t i = 0; i < n; ++i){Singleton::GetInstance()->Add("t2线程:" + to_string(rand()));}});t1.join();t2.join();Singleton::GetInstance()->Print();return 0;
}

懒汉模式:

懒汉模式顾名思义:只有在第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制

如果单例对象构造十分耗时或者占用很多资源,比如加载插件、初始化网络连接、读取文件等等,而有可能该对象程序运行时不会用到。但也要在程序一开始就进行初始化, 就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好 、

懒汉模式的实现相比于饿汉模式更加复杂。既然是手动启用实例,就需要考虑手动释放实例问题,手动释放实例之后不能影响自动释放实例,并且也不能重复释放

自动释放问题:定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象

懒汉模式中需要考虑线程安全问题:因此设计双检查加锁,第一次检查用于提高效率,避免每次访问单例都加减锁;第二次检查用于保证线程安全并确保单例只new一次

私有类内有两个锁,一个全局锁一个局部锁,全局锁存在的目的是使得单例获取与释放时都全局同一,保障全局唯一单例

#include<iostream>
#include<mutex>
#include<thread>
#include<vector>
#include<string>
#include<time.h>
using namespace std;//懒汉模式
//第一次调用时才会创建单例
class Singleton
{
public:~Singleton(){//程序可能有持久化需求,要求在程序结束时,将数据写到文件中}static Singleton* GetInstance(){//双检查加锁if (_ins == nullptr)//用于提高效率 避免每次访问单例都加减锁{_imtx.lock();if (_ins == nullptr)//保证线程安全和只new一次{_ins = new Singleton;}_imtx.unlock();}return _ins;}void Add(const string& str){_vmtx.lock();_v.push_back(str);_vmtx.unlock();}void Print(){_vmtx.lock();for (auto& e : _v){cout << e << endl;}cout << endl;_vmtx.unlock();}//显示手动释放单例static void DelInstance()//一般全局都要使用单例对象,所以一般情况下不需要显示释放{_imtx.lock();if (_ins){delete _ins;_ins = nullptr;//显示释放后置空,这样自动释放重复也不影响}_imtx.unlock();}//保证单例对象的回收(自动回收)class GC{public:~GC(){DelInstance();}};static GC _gc;private:Singleton() {}//限制类外随意创建对象//没有处理拷贝构造,是由于锁的存在,默认生成的拷贝构造//实际上仍然需要防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;private:mutex _vmtx;vector<string> _v;static Singleton* _ins;//静态成员类外实现static mutex _imtx;
};Singleton* Singleton::_ins = nullptr;
mutex Singleton::_imtx;Singleton::GC Singleton::_gc;int main()
{srand(time(0));int n = 30;thread t1([n]() {for (size_t i = 0; i < n; ++i){Singleton::GetInstance()->Add("t1线程:" + to_string(rand()));}});thread t2([n]() {for (size_t i = 0; i < n; ++i){Singleton::GetInstance()->Add("t2线程:" + to_string(rand()));}});t1.join();t2.join();Singleton::GetInstance()->Print();return 0;
}

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

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

相关文章

uni-app android picker选择默认月份

微信小程序选中月份后下次再点开是上次的选中的月份&#xff0c;而编译的android应用只默认当前月份 <picker mode"date" ref"picker" :disabled"disabled" :value"date" fields"month" change"bindDateChange&quo…

【ML】分类问题

分类问题 classification&#xff1a;根据已知样本特征&#xff0c;判断输入样本属于哪种已知样本类。 常用入门案例&#xff1a;垃圾邮件检测、图像分类、手写数字识别、考试通过预测。 分类问题和回归问题的明显区别&#xff1a; 分类问题的结果是非连续型标签&#xff0c…

Netty入门指南之传统通信的问题

作者简介&#xff1a;☕️大家好&#xff0c;我是Aomsir&#xff0c;一个爱折腾的开发者&#xff01; 个人主页&#xff1a;Aomsir_Spring5应用专栏,Netty应用专栏,RPC应用专栏-CSDN博客 当前专栏&#xff1a;Netty应用专栏_Aomsir的博客-CSDN博客 文章目录 参考文献前言多线程…

基于APM(PIX)飞控和missionplanner制作遥控无人车-从零搭建自主pix无人车无人坦克

前面的步骤和无人机调试一样&#xff0c;可以参考无人机相关专栏。这里不再赘述。 1.安装完rover的固件后&#xff0c;链接gps并进行校准。旋转小车不同方向&#xff0c;完成校准&#xff0c;弹出成功窗口。 2.校准遥控器。 一定要确保遥控器模式准确&#xff0c;尤其是使用没…

轻量封装WebGPU渲染系统示例<20>- 美化一下元胞自动机(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/rendering/src/voxgpu/sample/GameOfLifePretty.ts 系统特性: 1. 用户态与系统态隔离。 2. 高频调用与低频调用隔离。 3. 面向用户的易用性封装。 4. 渲染数据(内外部相关资源)和渲染机制分离…

redis-plus-plus访问REDIS集群

编程语言&#xff1a;C 开源库&#xff1a;redis-plus-plus 接口类&#xff1a;RedisCluster 初始化需要输入任意一个结点的IP和端口&#xff0c;如果设置了密码&#xff0c;还需要密码的明文并使用ConnectionOptions类。 初始化完成后可以直接进行读/写操作。 RedisClust…

网络唤醒(Wake-on-LAN, WOL)

远程唤醒最简单的方法&#xff1a;DDNSTOOpenwrt网络唤醒&#xff0c;完美实现。 原帖-远程唤醒_超详细windows设置远程唤醒wol远程连接&#xff08;远程开机&#xff09; WOL Web# 访问 Wake on Lan Over The Interweb by Depicus 可以无需借助软件很方便的从网页前端唤醒远…

使用Anaconda安装TensorFlow环境以及没有搜到的报错的解决方法

1.在官网下载Anaconda 这一步几乎不会有人报错 下稳定的版本 或者最新的版本都可以 2.TensorFlow分两个版本 一个是用cpu跑 另一个是用gpu跑 显而易见 cpu的计算性能已经比不上现在主流的显卡了 所以有独显的电脑尽量安装gpu版本 CPU版本: 先给出cpu版本的安装方法: 打开A…

描述低轨星座的特点和通信挑战,以及它们在5G和B5G中的作用。

文章目录 2章4 章5章&#xff08;没看&#xff09;6章&#xff08;没看&#xff09; 2章 将卫星星座中每个物理链路中可实现的数据速率、传播延迟和多普勒频移与3GPP技术报告中的参数进行分析和比较[3]。 相关配置 面向连接的网络&#xff0c;预先简历链路 卫星和地面终端有…

Unraid 无法远程访问 Web UI 的解决方法

在将 Unraid 系统升级到 6.12.1 版本之后&#xff0c;发现无法通过 ZeroTier 或蒲公英在外网访问 Unraid 的 Web 页面&#xff0c;但是直接访问 Docker 的端口可以正常访问。 初步判断&#xff0c;这很有可能是默认的 80 端口出现了问题。Unraid 的 Web 服务器默认监听 80 端口…

自动化测试--验证邮件内容

场景 业务上有许多发送邮件的场景&#xff0c;发送的邮件基本上都是自动发送的&#xff0c;而且邮件内容是很重要的&#xff0c;对于邮件发没发送&#xff0c;发送的时间点对不对每次回归测试工作量太大了&#xff0c;所以考虑把这部分内容加入到自动化测试中 工具 python g…

了解计算机的大小端存储模式

我们在计算机中存储数据时&#xff0c;数据是如何组织和表示的是一个重要的问题。其中一个关键概念是 大小端存储模式&#xff08;Endianness&#xff09;&#xff0c;它描述了多字节数据在内存中的存储方式。本文将介绍大小端存储模式的原理、应用和区别。 什么是大小端存储模…

通过全流量查看部门或客户端网络使用情况

近年来&#xff0c;随着数字化转型和云计算服务的广泛应用&#xff0c;组织和企业对于网络带宽和性能的需求也在不断增长。 网络的稳定性、性能和安全性对于业务流程的顺畅运行至关重要。因此&#xff0c;了解部门或客户端网络的使用情况是网络管理和优化的关键。本文将通过Ne…

Docker数据管理、网络与Cgroup资源限制

目录 一、Docker的数据管理 1、数据卷 2、数据卷容器 3、端口映射 4、容器互联 二、Docker网络 2.1Docker网络实现原理 2.2Docker 的网络模式 3.3网络模式详解&#xff1a; host模式 container模式 none模式 bridge模式 自定义网络 创建自定义网络 三、Cgroup资源…

Maven修改仓库和镜像地址

目录 1、修改仓库地址2、修改镜像地址 1、修改仓库地址 使用IDEA时,如果不指定自己下载的Maven,idea会默认使用自带的Maven 3&#xff08;bundle)。maven 3默认的仓库路径一般是在c盘的用户文件夹中的.m2目录下&#xff1a; 当maven下的pom文件中的依赖逐渐增加时,maven仓库下…

k8s报错pause 3.2 解决方案

报错 Failed to create pod sandbox: rpc error: code Unknown desc failed to get sandbox image "k8s.gcr.io/pause:3.2": failed to pull image "k8s.gcr.io/pause:3.2": failed to pull and unpack image "k8s.gcr.io/pause:3.2": failed…

Hook函数

在嵌入式系统中&#xff0c;hook函数&#xff08;也被称为钩子函数&#xff09;是一种特殊类型的函数&#xff0c;它会在特定的事件发生时被操作系统内部调用。例如&#xff0c;在实时操作系统&#xff08;RTOS&#xff09;中&#xff0c;如果删除了一个任务&#xff0c;就会调…

0基础学习VR全景平台篇第116篇:认识修图软件Photoshop

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 今天给大家讲解修图软件Photoshop&#xff0c;下面我们开始吧&#xff01; &#xff08;PS软件课程大纲&#xff09; 1.Photoshop是什么 发明人Adobe Photoshop&#xff0c;简称…

剑指Offer-推理二叉树

剑指Offer-推理二叉树 LCR 124. 推理二叉树 题目如下 某二叉树的先序遍历结果记录于整数数组 preorder&#xff0c;它的中序遍历结果记录于整数数组 inorder。请根据 preorder 和 inorder 的提示构造出这棵二叉树并返回其根节点。 注意&#xff1a;preorder 和 inorder 中均…

JavaScript作用域实战

● 首先&#xff0c;我们先创建一个函数&#xff0c;和以前一样&#xff0c;计算一个年龄的 function calcAge(birthYear) {const age 2037 - birthYear;return age; }● 然后我们创建一个全局变量&#xff0c;并调用这个函数 const firstName "IT知识一享"; cal…