shared_ptr 模拟实现

智能指针原理

智能指针基本上就是利用 RAII 技术实现的。资源取得时机便是初始化时机(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源的技术。在对象构造时获取资源,接着控制对资源的访问,使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源

智能指针的实现要考虑的问题:

  1. 怎么实现 RAII
  2. 如何重载 operator* 和 opertaor->
  3. 怎么复制智能指针对象

前两个问题比较简单,本文就不多做赘述了。下文主要介绍如何正确实现 shared_ptr 的复制函数。

shared_ptr

shared_ptr 这种智能指针访问对象采用共享所有权来管理其生存期。没有哪个特定的 shared_ptr 拥有该对象。取而代之的是,所有指涉到它的 shared_ptr 共同协作,确保在不再需要该对象的时刻将其析构。当最后一个指涉到某对象的 shared_ptr 不再指涉到它时,该 shared_ptr 会析构其指涉到的对象。

因此需要知道有多少个 shared_ptr 指向同一个资源。我们可以用一个引用计数,该计数在构造的时候初始化,复制的时候只需要将该值加 1 即可。经复制得到的对象共享同一个引用计数。

用 static int 实现引用计数可以吗?

既然我们需要多个对象共享同一个引用计数,那使用静态变量可以吗?

这是不行的,使用静态变量是可以做到共享,但静态变量在整个类中只有一个。也就是说,我们定义出的所有对象,共享同一个计数,这明显是不行的。

用 int 实现引用计数可以吗?

很明显不可以。当我们用复制一个 shared_ptr 类型对象时,我们获取到的是 int 类型的值,两个对象没有任何关联。

那用指针实现引用计数可以吗?

这是可以的。

假如我们用 int* 实现计数。在构造函数中,我们为指针 new 一块空间,并初始化为 1,表示有一个 shared_ptr 指向该对象。在复制构造函数中,我们直接复制指针的值,这样两个指针指向的实际是同一块空间,将指向的空间的值加 1 即可。

上面这样在多线程情况下会有问题,因此我们需要用一些方式来保护对临界资源的访问。下面分别用互斥锁和原子变量两种方式实现。

互斥锁

#include <iostream>
#include <mutex>
using namespace std;template<class T>
class SharedPtr {public:SharedPtr(T* ptr) : _data(ptr),_cnt(new int(1)),_mtx(new mutex) {cout << "构造函数" << endl;} ~SharedPtr() {bool deleteFlag = false;_mtx->lock();if ((*_cnt)-- == 1) {delete _data;delete _cnt;deleteFlag = true;}_mtx->unlock();if (deleteFlag) {cout << "析构函数" << endl;delete _mtx;}}SharedPtr(const SharedPtr<T>& sp) : _data(sp._data),_cnt(sp._cnt),_mtx(sp._mtx) {_mtx->lock();(*_cnt)++;_mtx->unlock();}SharedPtr<T>& operator=(const SharedPtr<T>& sp) {SharedPtr<T> tmp = sp;Swap(tmp);return *this;}private:void Swap(SharedPtr<T>& other) {std::swap(_data, other._data);std::swap(_cnt, other._cnt);std::swap(_mtx, other._mtx);}private:T* _data;int* _cnt;mutex* _mtx;
};int main() {SharedPtr<int> sp1(new int(10));SharedPtr<int> sp2(sp1);SharedPtr<int> sp3(new int(1));sp3 = sp2;return 0;
}

原子变量

在上面的实现方式中,我们用了互斥锁来保护计数,以实现原子性的加减。我们也可以直接用 C++ 提供的原子类型变量。

#include <atomic>
#include <iostream>
using namespace std;class RefCnt {public:RefCnt(): _cnt(1) {}int AddRef() {return ++_cnt;}int SubRef() {return --_cnt;}private:atomic<int> _cnt;
};template<class T>
class SharedPtr {public:SharedPtr(T* ptr) : _data(ptr),_refCnt(new RefCnt) {cout << "构造函数" << endl;}~SharedPtr() {if (_refCnt->SubRef() == 0) {delete _data;delete _refCnt;cout << "析构函数" << endl;}}SharedPtr(const SharedPtr<T>& sp) : _data(sp._data),_refCnt(sp._refCnt) {_refCnt->AddRef();}SharedPtr<T>& operator=(const SharedPtr<T>& sp) {SharedPtr<T> tmp = sp;Swap(tmp);return *this;}private:void Swap(SharedPtr<T>& other) {std::swap(_data, other._data);std::swap(_refCnt, other._refCnt);}private:T* _data;RefCnt* _refCnt;
};int main() {SharedPtr<int> sp1(new int(10));SharedPtr<int> sp2(sp1);SharedPtr<int> sp3(new int(1));sp3 = sp2;return 0;
}

代码比起使用互斥锁的方法简单了不少。

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

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

相关文章

智能优化算法应用:基于热交换算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于热交换算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于热交换算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.热交换算法4.实验参数设定5.算法结果6.参考文献7.…

Bishop新著 - 深度学习:基础与概念 - 前言

译者的话 十几年前&#xff0c;笔者在MSRA实习的时候&#xff0c;就接触到了Christopher M, Bishop的经典巨著《Pattern Recogition and Machine Learning》(一般大家简称为PRML)。Bishop大神是微软剑桥研究院实验室主任&#xff0c;物理出身&#xff0c;对机器学习的基本概念…

客户销售目标拆解:数据驱动的方法和策略

写在开头 在当今竞争激烈的商业环境中,企业需要更加精准地制定销售目标以实现业务增长。数据驱动的方法在这一过程中扮演着关键的角色,帮助企业深入了解客户特征、行为和需求。本篇博客将深入探讨销售目标拆解在企业管理中的重要性,并介绍如何利用数据驱动的方法和策略来制…

Leetcode 2954. Count the Number of Infection Sequences

Leetcode 2954. Count the Number of Infection Sequences 1. 解题思路2. 代码实现 题目链接&#xff1a;2954. Count the Number of Infection Sequences 1. 解题思路 这道题其实思路上还是挺简单的&#xff0c;就是一个数学问题&#xff0c;还是那种不太难的数学问题。 显…

免费数据采集软件,多种数据采集方式

数据无疑是企业决策的关键驱动力。要充分利用数据&#xff0c;就需要进行数据收集&#xff0c;而数据采集的方式多种多样。 数据采集方式的丰富多彩 数据采集并非一蹴而就的简单任务&#xff0c;而是一个多层次、多步骤的过程。在这个过程中&#xff0c;我们有着多种数据采集…

VS2022配置WinPcap开发

winpcap 官网&#xff1a;http://www.winpcap.org/ 1.首先下载安装 winpcap.exe&#xff0c;http://www.winpcap.org/install/default.htm 目的是安装相关驱动和 dll&#xff0c;安装完成之后基于 winpcap 的应用程序才能够正常运行。 2.下载 winpcap 的开发包&#xff0c;头文…

【Java】集合 之 使用EnumMap

使用 EnumMap 因为HashMap是一种通过对key计算hashCode()&#xff0c;通过空间换时间的方式&#xff0c;直接定位到value所在的内部数组的索引&#xff0c;因此&#xff0c;查找效率非常高。 如果作为key的对象是enum类型&#xff0c;那么&#xff0c;还可以使用Java集合库提…

FFmpeg之将视频转为16:9(横屏)或9:16(竖屏)(三十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…

如何判断台灯是否伤眼?分享考研必备的护眼台灯

台灯可以说是我们日常生活中必不可少的一盏灯具&#xff0c;可以在夜晚的时候给我们带来充足的照明环境&#xff01;而且近年来儿童青少年的近视率都非常之高&#xff0c;不少家长们为了保护孩子视力选择专业的台灯&#xff0c;因为专业的台灯对眼睛是有许多好处的&#xff0c;…

记录华为云服务器(Linux 可视化 宝塔面板)-- Nginx配置出现500错误记录

文章目录 1、路由配置&#xff0c;访问显示500如有启发&#xff0c;可点赞收藏哟~ 1、路由配置&#xff0c;访问显示500 错误如图显示500 解决思路如下 1、先查看错误日志 错误日志存放位置 提示 /login配置的文件有问题 开始配置如下图 修改前 修改后&#xff08;即在/l…

世岩清上:如何做好学校课件视频

学校课件制作是教育信息化时代不可或缺的一部分。通过精心的课件制作&#xff0c;教师可以更好地呈现知识点&#xff0c;激发学生的学习兴趣&#xff0c;提高教学效果。 一、课件制作的重要性 随着信息技术的不断发展&#xff0c;教育行业逐渐引入了各种先进的技术手段&#…

echarts笔记-GeoJSON河北数据下并裁剪为冀北地图并使用echarts加载

首先找个网站把河北的GeoJSON数据下载下来&#xff0c;我用的是这个&#xff0c;理论上任意一个都可以 DataV.GeoAtlas地理小工具系列 将json数据下载后&#xff0c;进行裁剪&#xff0c;仅保留冀北数据。 如下&#xff0c;我裁剪的数据&#xff1a; {"type": &qu…

网工学习9-STP配置

如图 1 所示&#xff0c;当前网络中存在环路&#xff0c; SwitchA 、SwitchB 、SwitchC 和 SwitchD 都运行 STP&#xff0c;通过 彼此交互信息发现网络中的环路&#xff0c;并有选择的对某个端口进行阻塞&#xff0c;最终将环形网络结构修剪成无 环路的树形网络结构&#xff…

leetcode 201 数字范围按位与

leetcode 201 题目题解代码 题目 给你两个整数 left 和 right &#xff0c;表示区间 [left, right] &#xff0c;返回此区间内所有数字 按位与 的结果&#xff08;包含 left、right 端点&#xff09;。 具体示例如下&#xff1a; 题解 本题是一个在思维上的方法&#xff0c;不…

怎么理解回流和重绘?

回流&#xff08;reflow&#xff09;和 重绘&#xff08;repaint&#xff09;是浏览器渲染过程中的两个关键概念。 一、概念&#xff1a; 回流指的是浏览器在计算文档流布局&#xff08;layout&#xff09;时&#xff0c;重新计算元素的位置和大小的过程。当页面中的元素发生尺…

Leetcode—1038.从二叉搜索树到更大和树【中等】

2023每日刷题&#xff08;四十九&#xff09; Leetcode—1038.从二叉搜索树到更大和树 算法思想 二叉搜索树的中序遍历&#xff08;左根右&#xff09;结果是一个单调递增的有序序列&#xff0c;我们反序进行中序遍历&#xff08;右根左&#xff09;&#xff0c;即可以得到一…

【数组】-Lc136-只出现一次的数字(异或运算)

写在前面 最近想复习一下数据结构与算法相关的内容&#xff0c;找一些题来做一做。如有更好思路&#xff0c;欢迎指正。 目录 写在前面一、场景描述二、具体步骤1.环境说明2.代码 写在后面 一、场景描述 给定一个非空整数数组&#xff0c;除了某个元素只出现一次以外&#xff0…

网络层之SDN基本概念、路由算法和路由协议

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

算法与数据结构(二十五)TopK问题:基于快排的Python模板

首先&#xff0c;先写partition模板 def partition(nums, left, right):pivot nums[left]#初始化一个待比较数据i,j left, rightwhile(i < j):while(i<j and nums[j]>pivot): #从后往前查找&#xff0c;直到找到一个比pivot更小的数j-1nums[i] nums[j] #将更小的数…

自然语言处理:电脑如何理解我们的语言?

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 ​编辑 常见方法 1.基于词典的方法 2.基于计数的方法 基于推理的方法 Bert input_ids attention_mask token_type_ids 结语 在广…