C++ | shared_ptr与weak_ptr

2023-05-16

文章目录

  • 前言
  • 一、shared_ptr与weak_ptr是什么?
    • 1.shared_ptr的内存模型
    • 2.weak_ptr的内存模型
  • 二、仿写系统的shared_ptr与weak_ptr
    • 1.mdeletor
    • 2.Ref_con
    • 3.shared_ptr
    • 4.weak_ptr
  • 三、解决循环引用问题
  • 四、总结


前言

简单介绍shared_ptr与weak_ptr,仿写系统的shared_ptr与weak_ptr,并解决循环引用的问题.


提示:以下是本篇文章正文内容,下面案例可供参考

一、shared_ptr与weak_ptr是什么?

shared_ptr是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。
weak_ptr是为配合shared_ptr而引入的一种智能指针。

1.shared_ptr的内存模型

在这里插入图片描述

2.weak_ptr的内存模型

在这里插入图片描述

二、仿写系统的shared_ptr与weak_ptr

1.mdeletor


```cpp
class Mdeletor
{
public:
	Mdeletor() = default;
	void operator()(_Ty* p)const
	{
		if (p != NULL)
		{
			delete p;
		}
		p = NULL;
	}
};

template<typename _Ty>
class Mdeletor<_Ty[]>
{
public:
	Mdeletor() = default;
	void operator()(_Ty* p)const
	{
		if (p != NULL)
		{
			delete[]p;
		}
		p = NULL;
	}
};

2.Ref_con

template<typename _Ty>
class RefCnt
{
protected:
	_Ty* ptr;
	std::atomic_int Uses;
	std::atomic_int Weaks;
public:
	RefCnt(_Ty* p) :ptr(p), Uses(1), Weaks(1) {}
	~RefCnt() {}
	void IncUses()
	{
		Uses += 1;
	}
	void IncWeaks()
	{
		Weaks += 1;
	}
	template<typename _Ty, typename _Dx>
	friend class my_shared_ptr;

	template<typename _Ty>
	friend class my_weak_ptr;
};

3.shared_ptr

代码如下(示例):

template<typename _Ty,typename _Dx= Mdeletor<_Ty>>
class my_shared_ptr
{
private:
	_Ty* Ptr;
	RefCnt<_Ty>* Ref;
	_Dx mdeletor;
public:
	my_shared_ptr(_Ty* p = nullptr) :Ptr(nullptr),Ref(nullptr)
	{
		if (p != nullptr)
		{
			Ptr = p;
			Ref = new RefCnt<_Ty>(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& other):Ptr(other.Ptr),Ref(other.Ref)//拷贝构造
	{
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
	}
	my_shared_ptr(my_shared_ptr&& other) :Ptr(other.Ptr), Ref(other.Ref)//移动构造
	{
		other.Ptr = NULL;
		other.Ref = NULL;
	}

	my_shared_ptr& operator=(const my_shared_ptr& other)//赋值
	{
		if (this == &other || Ptr == other.Ptr)  return *this;//自赋值,直接返回本身
		
		if (Ptr != NULL && --Ref->Uses == 0)//被赋值的智能指针对象拥有资源,
		{                                   //且该对象仅被该智能指针拥有
			mdeletor(Ptr);//释放该对象
			if (--Ref->Weaks == 0)//当弱引用计数为零时
			{
				delete Ref;//析构引用计数对象
				Ref = NULL;
			}
		}

		Ptr = other.Ptr;
		Ref = other.Ref;
		if (Ptr != NULL)
		{
			Ref->IncUses();
		}
		return *this;
	}

	my_shared_ptr& operator=(my_shared_ptr&& other)//移动赋值
	{
		if (this == &other)  return *this;
		if (Ptr == other.Ptr && Ptr != NULL)//当两个智能指针使用同一个对象时,且该对象不为空
		{
			other.Ptr = NULL;//去掉other的使用权
			other.Ref = NULL;
			Ref->Uses -= 1;//强引用计数-1

			return *this;
		}

		if (Ptr != NULL && --Ref->Uses == 0)
		{
			mdeletor(Ptr);
			if (--Ref->Weaks == 0)
			{
				delete Ref;
				Ref = NULL;
			}
		}
		Ptr = other.Ptr;
		Ref = other.Ref;

		other.Ptr = NULL;
		other.Ref = NULL;

		return *this;
	}

	~my_shared_ptr()
	{
		if (Ptr != NULL && --Ref->Uses == 0)
		{
			mdeletor(Ptr);
			if (--Ref->Weaks == 0)
			{
				delete Ref;
			}
		}
		Ref = NULL;
	}

	_Ty* get()const
	{
		return Ptr;
	}

	_Ty& operator*()
	{
		return *get();
	}

	_Ty* operator->()
	{
		return get();
	}

	size_t use_count()const
	{
		if (Ref == NULL)  return 0;
		return Ref->Uses;
	}

	void swap(my_shared_ptr& other)
	{
		std::swap(Ptr, other.Ptr);
		std::swap(Ref, other.Ref);
	}

	operator bool()const
	{
		return Ptr != NULL;
	}
	template<typename _Ty>
	friend class my_weak_ptr;
};

4.weak_ptr

代码如下(示例):

template<typename _Ty>
class my_weak_ptr
{
private:
	RefCnt<_Ty>* wRef;
public:
	my_weak_ptr() :wRef(NULL) {}
	my_weak_ptr(const my_shared_ptr<_Ty>& other) :wRef(other.Ref)//共享指针构造
	{
		if (wRef!=NULL)
		{
			wRef->IncWeaks();
		}
	}

	my_weak_ptr(const my_weak_ptr& other) :wRef(other.wRef)//拷贝构造
	{
		if (wRef != NULL)
		{
			wRef->IncWeaks();
		}
	}

	my_weak_ptr(my_weak_ptr&& other) :wRef(other.wRef)//移动构造
	{
		other.wRef = NULL;
	}

	my_weak_ptr& operator=(const my_weak_ptr& other)
	{
		if (this == &other||wRef=other.wRef)  return *this;//自赋值或者是两个指针指向同一个对象

		if (this != NULL && --wRef->Weaks == 0)//是否自己独占对象
		{
			delete wRef;
		}

		wRef = other.wRef;
		if (wRef != NULL)
		{
			wRef->IncUses();
		}

		return *this;
	}
	my_weak_ptr& operator=(my_weak_ptr&& other)
	{
		//1 判断是否自赋值
		if (this == &other)  return *this;

		//2 判断是否是指向同一个对象的两个指针相互赋值
		if (wRef == other.wRef && wRef != NULL)//如果是
		{
			other.wRef = NULL;
			wRef->Weaks -= 1;
			return *this;
		}

		//3 两个指向不同对象的指针赋值
		if (this != NULL && --wRef->Weaks == 0)//是否自己独占对象
		{
			delete wRef;//如果独有
		}

		wRef = other.wRef;
		other.wRef = NULL;
		
		return *this;
	}
	my_weak_ptr& operator=(const my_shared_ptr<_Ty>& other)//共享智能指针给弱指针赋值
	{
		if (wRef == other.Ref)  return *this;

		if (wRef != NULL && --wRef->Uses == 0)
		{
			delete wRef;
		}
		wRef = other.Ref;

		if (wRef != NULL)
		{
			wRef->IncWeaks();
		}

		return *this;
	}
	my_weak_ptr& operator=( my_shared_ptr<_Ty>&& other) = delete;
	~my_weak_ptr()
	{
		if (wRef != NULL && --wRef->Weaks == 0)
		{
			delete wRef;
			
		}
		wRef = NULL;
	}
	bool expired()const//判断被引用的对象是否删除,若删除则返回真
	{
		return wRef->Uses == 0;
	}
	my_shared_ptr<_Ty> lock()const
	{
		my_shared_ptr<_Ty>tmp;
		tmp.Ptr = wRef->ptr;
		tmp.Ref = wRef;
		tmp.Ref->IncUses();
		return tmp;

	}
};

该处使用的url网络请求的数据。


三、解决循环引用问题

在这里插入图片描述

四、总结

weak_ptr一般需要与shared_ptr联合使用,且若要使用weak_ptr时需要用lock()函数返回一个shared_ptr的对象再进行使用。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ | shared_ptr与weak_ptr 的相关文章

  • error while loading shared libraries: libopencv_imgcodecs.so.3.4

    最近给电脑重新安装了opencv3 4 10 xff0c 但是跑工程时却出现这个问题 xff0c 网上百度了一堆 xff0c 发现应该是库设置的问题 xff0c 但是到底是哪里出了问题 xff0c 怎么设置 xff0c 我根据我自己的实际情
  • 关于 make_unique 和 make_shared

    C 43 43 14 才加入make unique xff0c 据说当时忘记实现了 那么C 43 43 11 可以自己实现这个功能 xff1a template lt typename T typename Args gt std uniq
  • 智能指针tr1::shared_ptr、boost::shared_ptr使用

    对于tr1 shared ptr在安装vs同时会自带安装 xff0c 但是版本较低的不存在 而boost作为tr1的实现品 xff0c 包含 Algorithms Broken Compiler Workarounds Concurrent
  • C++11中unique_ptr的使用

    在C 43 43 中 xff0c 动态内存的管理是通过一对运算符来完成的 xff1a new xff0c 在动态内存中为对象分配空间并返回一个指向该对象的指针 xff0c 可以选择对对象进行初始化 xff1b delete xff0c 接受
  • error while loading shared libraries: lib*.so: cannot open shared object file: No such file

    linux在编译文件时报错 xff1a slam sample error span class token keyword while span loading shared libraries libslam common so can
  • error while loading shared libraries : libts-0.0.so.0:cannot open shared object file: No such file o

    这是我在运行自己写的qt程序时 xff0c 爆出的错误 xff0c 从错误的地方来看 xff0c 是我们的库中缺少一个libts 0 0 so 0的动态库 xff0c 如果开发经验比较丰富的人都会知道这个库是tslib的一个库 xff0c
  • 错误./hello: error while loading shared libraries: libQtGui.so.4: cannot open shared object file:

    之前一直想在ARM 上跑qt xff0c 但都出现错误 xff1a hello error while loading shared libraries libQtGui so 4 cannot open shared object fil
  • weak & asign

    Why does Apple use assign rather than weak to store a delegate http stackoverflow com questions 20419317 why does apple
  • 访问共享网络文件夹

    我需要通过 VBA 访问网络文件服务器上托管的文件夹 该文件夹只能通过我有用户名和密码的服务帐户 与普通用户帐户不同 以书面形式访问 通过 UI 我可以看到该文件夹 并将其映射为本地驱动器 但为了以书面形式访问它 我需要从 Windows
  • Android - 对话框中的共享元素转换

    我想知道是否有任何方法可以在活动 片段和对话框之间使用共享元素 我有一个包含对话框的项目 我想在 Activity 视图层次结构中的 ImageView 到 GalleryDialog 中的相关 ImageView 之间进行转换 我搜索了一
  • 在具有多个模块(如 JHipster)的项目中嵌套角度组件

    我试图在另一个实体组件中显示一个实体组件 我在网上找到了一些关于共享模块的信息 我也检查了这个post https stackoverflow com questions 42284351 jhipster 4 how to put ent
  • VB .NET 共享函数(如果同时调用多次)

    考虑我有一个共享功能 Public Shared Function CalculateAreaFromRadius ByVal radius As Double As Double square the radius Dim radiusS
  • 容器中的共享库

    对于两个进程A和B 都使用库libc so libc so只加载到内存一次 当 A 和 B 都运行在同一主机和同一 rootfs 上时 这是正常情况 对于容器来说 如果A和B运行在不同的容器中 A和B是否共享相同的内存区域 例如 image
  • Java中共享内存的任何概念

    AFAIK Java中的内存是基于堆的 内存是动态分配给对象的 并且没有共享内存的概念 如果没有共享内存的概念 那么Java程序之间的通信应该是很耗时的 在 C 中 与其他通信模式相比 通过共享内存进行进程间通信更快 如我错了请纠正我 另外
  • Outlook Mapi 访问共享联系人

    我想通过 Mapi 从 Outlook 导入联系人 第一步使用标准接触是没有问题的 MAPIFolder contactObjects outlookObj Session GetDefaultFolder OlDefaultFolders
  • 通过 EWS 和 C# 访问没有邮箱的资源日历

    我们的 Exchange 管理员 Exchange 2010 SP1 设置了共享资源日历 没有分配给该资源日历的邮箱 我希望能够使用 EWS 和 C 阅读会议 Snippet ExchangeService esvc new Exchang
  • C++ 进程间通信的最佳方式

    我有两个进程 一个进程将查询另一个进程的数据 在有限的时间内 每秒 10000 个 将会有大量的查询 并且每秒将传输数据 gt 100 mb 数据类型将是整数类型 双精度 整数 我的问题是用什么方式连接这个过程 共享内存 消息队列 lpc
  • 在应用程序和 Web 之间共享数据库

    我参与了一个必须从现有数据库检索查询的应用程序 该数据库必须在远程服务器中的 php 中实现 并且将是管理员必须将内容插入共享数据库的地方 但我不知道如何正确实现或什么是最佳解决方案 我正在考虑使用 php 创建一个 sqlite 数据库并
  • 在共享主机上从 HTML 页面生成 PDF 文件

    我在主机上启用扩展等的权限非常有限 但我希望通过 PHP 从 HTML 页面 带有 css 图像 生成 PDF 我有什么想法可以通过近乎零的 CL 访问等来实现这一点吗 最好不是 黑客 依赖服务 因为我将寻求长期使用 生成要呈现到 PDF
  • 适用于 Linux 的 NUMA 感知命名共享内存

    Windows API 提供了 CreateFileMappingNuma 函数 http msdn microsoft com en us library windows desktop aa366539 v vs 85 aspx htt

随机推荐

  • 无线收发模块——NRF24L01

    1 什么是nRF24L01 nRF24L01是由NORDIC生产的工作在2 4GHz 2 5GHz的ISM 频段的单片无线收发器芯片 有着极低的电流消耗 nRF24L01与5V单片机的连接通过SPI接口进行通讯 xff0c 输出功率频道选择
  • 使用 monitor command 监控 QEMU 运行状态

    使用 monitor command 监控 QEMU 运行状态 在虚拟化的研究领域 xff0c QEMU 有着举足轻重的地位 2007 年 2 月发布的 Linux 2 6 20 内核中 xff0c 集成了 KVM 作为其虚拟化的具体实现
  • 基于STM32的多普勒雷达测速

    基于多普勒雷达传感器 xff0c 以STM32单片机为主控芯片 xff0c 根据不同模块检测距离的不同 xff0c 使用不同多普勒雷达传感器实现对远近距离车辆行驶速度及方向的测量 1 基础知识 雷达 雷达英文为Radar xff0c Rad
  • 语音合成芯片——SYN6658

    一 SYN6658 SYN6658是中文语音合成芯片 xff0c 通过UART 接口或SPI 接口通讯方式 xff0c 接收待合成的文本数据 xff0c 实现文本到语音的转换 可以采用GB2312 GBK BIG5 和Unicode 四种编
  • c++学习笔记(一)新手区分C语言、C++、VC++

    我认为第一件事需要跟各位说清楚的就是C语言和C 43 43 以及VC 43 43 之间的区别 特别是许多朋友一开始就喜欢下载使用VS xff08 Visual Studio xff09 xff0c 所以我认为这很有必要跟大家说清楚 xff0
  • Spring Secuirty 密码加密认证讲解

    目录 一 密码加密介绍 1 1 常见加密的策略 1 Hash 算法 2 单向自适应函数 二 Security加密结构 2 1 PasswordEncoder 2 2 密码认证流程 2 3 DeletaingPasswordEncoder 1
  • Gazebo添加动态障碍物插件及插件配置过程

    1 运行空白环境 43 添加动态障碍物 参考https blog csdn net zyh821351004 article details 128203687 actor标签范围内的模型配置 人会在多点间运动 span class tok
  • Linux多线程 | 线程同步

    文章目录 前言主要介绍四种常用的线程同步方式以及相关的函数接口 一 线程同步二 同步方法1 互斥锁2 信号量3 条件变量4 读写锁 总结 前言 主要介绍四种常用的线程同步方式以及相关的函数接口 提示 xff1a 以下是本篇文章正文内容 xf
  • Linux多线程 | 线程安全、多线程中执行fork()

    文章目录 前言一 线程安全二 线程安全函数1 以strtok为例子2 输出结果 三 多线程执行fork 1 主函数中执行fork 2 线程函数中执行fork 总结 前言 本篇文章主要讲述怎么保证线程安全 提示 xff1a 以下是本篇文章正文
  • Linux网络编程 | TCP详解

    文章目录 前言一 TCP是什么二 TCP粘包问题三 TCP怎么保证可靠性四 TCP三次握手 xff0c 四次挥手五 TCP状态转移图总结 前言 总结TCP相关问题 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一
  • Linux网络编程 | UDP编程

    文章目录 前言一 UDP是什么二 UDP 数据报服务特点二 UDP 编程流程1 服务器2 客户端3 输出结果 总结 前言 浅谈UDP 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 UDP是什么 UDP是一种不可
  • Linux网络编程 | HTTP、Web服务器

    提示 xff1a 写完文章后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言一 http协议二 请求报文三 应答报文四 实现简单的Web服务器1 代码如下2 输出结果 xff1a 总结 前言 介绍ht
  • Multipath多路径冗余全解

    一 什么是multipath 普通的电脑主机都是一个硬盘挂接到一个总线上 xff0c 这里是一对一的关系 而到了有光纤组成的SAN环境 xff0c 由于主机和存储通过了光纤交换机连接 xff0c 这样的话 xff0c 就构成了多对多的关系
  • Linux网络编程 | I/O复用之select

    文章目录 前言一 select二 API接口 xff1a 三 使用步骤1 服务器端2 客户端 总结 前言 select的原理以及使用 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 select select系统
  • Linux网络编程 | I/O复用之poll

    文章目录 前言一 poll二 API接口三 使用步骤1 服务器端2 客户端 总结 前言 poll的原理以及使用 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 poll poll 系统调用和 select 类似
  • Linux网络编程 | I/O复用之epoll(LT模式)

    文章目录 前言一 epoll二 常用API xff1a 三 使用步骤1 服务器端 xff08 LT模式 xff09 2 客户端 总结 前言 epoll原理以及使用 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一
  • Linux网络编程 | I/O复用之epoll(ET模式)

    文章目录 前言一 epoll的LT模式与ET模式二 使用步骤1 服务器端 xff08 ET xff09 2 客户端 总结 前言 epoll xff08 ET模式 xff09 以及使用方法 提示 xff1a 以下是本篇文章正文内容 xff0c
  • Linux网络编程 | Libevent库

    文章目录 前言一 libevent二 Libevent模型1 模型图2 结构图 三 支持事件类型四 使用libevent完成TCP服务器端1 服务器端 总结 前言 简单介绍libevent库以及使用 提示 xff1a 以下是本篇文章正文内容
  • Linux基础 | 守护进程

    文章目录 前言一 守护进程是什么 xff1f 二 编程流程三 使用步骤1 后台运行 xff0c 每隔五秒输出一次时间2 输出结果 总结 前言 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 守护进程是什么 xff
  • C++ | shared_ptr与weak_ptr

    文章目录 前言一 shared ptr与weak ptr是什么 xff1f 1 shared ptr的内存模型2 weak ptr的内存模型 二 仿写系统的shared ptr与weak ptr1 mdeletor2 Ref con3 sh