std::weak_ptr(分析、仿写)

news2025/7/12 7:35:29

目录

一、为什么会有weak_ptr?

1、看一个例子

2.weak_ptr 是什么?

3.weak_ ptr 如何使用?

1、如何创建weak_ ptr 实例

 2、如何判断weak_ptr指向的对象是否存在

 3、weak_ptr的使用

 二、仿写std::weak_ptr

1、c++参考手册

 2、代码


一、为什么会有weak_ptr?

1、看一个例子

class Child;
class Parent {
public:
	shared_ptr<Child> _child;
	~Parent() {
		cout << " Destroy Parent" << endl;
	}
	void hi()const {
		cout << "hello" << endl;
	}
};
class Child {
public:
	shared_ptr<Parent> parent;
	~Child() {
		cout << " Bey child" << endl;
	}
};
int main() {
	shared_ptr<Parent>par = make_shared<Parent>();
	shared_ptr<Child>pch = make_shared<Child>();
	par->_child = pch;
	pch->parent = par;
	pch->parent->hi();
	return 0;
}

 到最后还是没有完成析构。 

上面代码的运行结果,只打印出”Hello",而并没有打印出"Bye Parent"或"Bye Child",说明Parent和Child的析构函数并没有调用到。这是因为Parent和Child对象内部,具有各自指向对方的shared _ptr,加上parent和child这两个shared_ptr, 说明每个对象的引用计数都是2。当程序退出时,即使parent和child被销毁,也仅仅是导致引用计数变为了1,因此并未销毁Parent和Child对象。

为了解决类似这样的问题,C++11 引入了weak_ptr,来打破这种循环引用。

2.weak_ptr 是什么?

weak ptr是为了配合shared _ptr 而引入的一种智能指针,它指向一个由shared_ptr 管理的对象而不影响所指对象的生命周期,也就是将一个weak_ptr 绑定到一个shared_ptr不会改变shared_ptr 的引用计数。不论是否有weak_ptr 指向,一旦最后一个指向对象的shared_ptr 被销毁,对象就会被释放。从这个角度看,weak_ptr 更像是shared_ptr 的一个助手而不是智能指针。weak_ptr并不拥有对动态对象的管辖权,weak_ptr 指向shared_ptr 的目标也不会增加计数器的值,相反,weak_ptr 拥有一套不纳入计数器的指针系统。

3.weak_ ptr 如何使用?

接下来,我们来看看weak_ptr的简单用法。

1、如何创建weak_ ptr 实例

当我们创建一个weak_ptr 时,需要用一个shared_ptr实例来初始化weak_ptr,由于是弱共享, weak_ ptr的创建并不会影响shared_ptr 的引用计数值。
示例:

 2、如何判断weak_ptr指向的对象是否存在

既然weak_ptr并不改变其所共享的shared_ptr实例的引用计数,那就可能存在weak_ptr指向的对象被释放掉这种情况。这时,我们就不能使用weak_ptr直接的访问对象。那么如何判断weak_ptr指向的对象存在呢?

c++提供lock函数来实现该功能。

如果对象存在,lock()函数返回一个指向共享对象的shared_ptr,否则返回一个空shared_ptr。

class Object {
private:
	int value;
public:
	Object(int x = 0) :value(x) { cout << "Object Create" << endl;; }
	~Object() { cout << "Object Destroy"<<endl; }
	int GetValue()const {
		return value;
	}
};
int main() {
	shared_ptr<Object>sp(new Object(10));
	weak_ptr<Object>wp(sp);
	if (shared_ptr<Object>pa = wp.lock()) {
		cout << pa->GetValue() << endl;
	}
	else {
		cout << wp.expired() << endl;//判断对象是否被销毁
		cout << "wp 引用对象为空" << endl;
	}
	return 0;
}

 3、weak_ptr的使用

weak_ptr没有重载operator->和operator *操作符号,无法访问对象,可以使用lock()访问原始对象;

class Child;
class Parent {
public:
	weak_ptr<Child> _child;
	~Parent() {
		cout << " Destroy Parent" << endl;
	}
	void hi()const {
		cout << "hello" << endl;
	}
};
class Child {
public:
	weak_ptr<Parent> parent;
	~Child() {
		cout << " Bey child" << endl;
	}
};
int main() {
	shared_ptr<Parent>par = make_shared<Parent>();
	shared_ptr<Child>pch = make_shared<Child>();
	par->_child = pch;
	pch->parent = par;
	if (!(pch->parent.expired())) {
		pch->parent.lock()->hi();
	}
	return 0;
}

 

 二、仿写std::weak_ptr

1、c++参考手册

 2、代码

#ifndef MY_WEAK_PTR
#define MY_WEAK_PTR
#include<atomic>
template<class _Ty>
class MyDeletor
{
public:
	MyDeletor() {}
	void operator() {_Ty* ptr}const
	{
		if (ptr != nullptr)
		{
			delete ptr;
		}
	}
};
template<class _Ty>
class MyDeletor<_Ty[]>
{
public:
	MyDeletor() = default;
	void operator() { _Ty* ptr }const
	{
		if (ptr != nullptr)
		{
			delete []ptr;
		}
	}
};
template <class _Ty>
class RefCnt
{
public:
	_Ty* _Ptr;
	std::atomic_int _Uses;
	std::atomic_int _Weaks;
public:
	RefCnt(_Ty* p) :_Ptr(p), _Uses(1), _Weaks(1) {}
	~RefCnt() {}
	void _Incref() { _Uses += 1; }
	void _Incwref() { _Weaks += 1; }
};
template<class _Ty,class _Dx=MyDeletor<_Ty>>
class my_shared_ptr
{
private:
	_Ty*         _Ptr;
	RefCnt<_Ty>* _Rep;
	_Dx _mDeletor;
public:
	my_shared_ptr(_Ty* p = nullptr) :_Ptr(nullptr), _Rep(nullptr)
	{
		if (p != nullptr)
		{
			_Ptr = p;
			_Rep = new RefCnt<_Ty>(p);
		}
	}
	my_shared_ptr(const my_shared_ptr& _Y) :_Ptr(_Y._Ptr), _Rep(_Y._Rep)
	{
		if (_Rep != nullptr)
		{
			_Rep->_Incref();
		}
	}
	my_shared_ptr(my_shared_ptr&& other):_Ptr(other._Ptr),_Rep(other._Rep)
	{
		other._Ptr = nullptr;
		other._Rep = nullptr;
	}
	my_shared_ptr& operator =(const my_shared_ptr& r)
	{
		if (this == &r || this->_Ptr == r._Ptr)return *this;
		if (_Ptr != nullptr && --_Rep->_Uses == 0)
		{
			_mDeletor(_Ptr);
			if (--_Rep->_Weaks == 0)
			{
				delete _Rep;
			}
		}
		_Ptr = r._Ptr;
		_Rep = r._Rep;
		if (_Ptr != nullptr)
		{
			_Rep->_Incref();
		}
		return *this;
	}
	my_shared_ptr& operator =(my_shared_ptr&& other)
	{
		if (this == &other)return *this;
		if (this->_Ptr != nullptr && other->_Ptr != nullptr && _Ptr == other->_Ptr)
		{
			this->_Rep->_Uses -= 1;
			other->_Ptr = nullptr;
			other->_Rep = nullptr;
			return *this;
		}
		if (_Ptr != nullptr && --_Rep->_Uses == 0)
		{
			_mDeletor(_Ptr);
			if (--_Rep->_Weaks == 0)
			{
				delete _Rep;
			}
		}
		_Ptr = other._Ptr;
		_Rep = other._Rep;
		other._Ptr = nullptr;
		other._Rep = nullptr;
		return *this;
	}
	~my_shared_ptr()
	{
		if (_Rep != nullptr && --_Rep->_Uses == 0)
		{
			_mDeletor(_Ptr);
			if (--_Rep->_Weaks == 0)
			{
				delete _Rep;
			}
		}
		_Ptr = nullptr;
		_Rep = nullptr;
	}
	_Ty* get()const { return _Ptr; }
	_Ty& operator*()const { return *get(); }
	_Ty* operator ->() const { return get(); }
	size_t use_count()const
	{
		if (_Rep == nullptr)return 0;
		return _Rep->_Uses;
	}
	void swap(my_shared_ptr& r)
	{
		std::swap(_Ptr, r._Ptr);
		std::swap(_Rep, r._Rep);
	}
	operator bool()const { return _Ptr != nullptr; }
};
template <class _Ty>
class my_weak_ptr
{
private:
	RefCnt<_Ty>* _Rep;
public:
	my_weak_ptr() :_Rep(nullptr) {}
	my_weak_ptr(const my_weak_ptr<_Ty>& other) :_Rep(other._Rep)
	{
		if (_Rep != nullptr)
		{
			_Rep->_Incwref();
		}
	}
	my_weak_ptr(const my_weak_ptr& other) :_Rep(other._Rep)
	{
		if (_Rep != nullptr)
		{
			_Rep->_Incwref();
		}
	}
	my_weak_ptr(my_weak_ptr&& other) :_Rep(other._Rep)
	{
		other._Rep = nullptr;
	}
	my_weak_ptr& operator =(const my_weak_ptr& other)
	{
		if (this == &other || this->_Rep == other._Rep)return *this;
		if (this->_Rep != nullptr && --_Rep->_Weaks == 0)
		{
			delete _Rep;
		}
		_Rep = other->_Rep;
		if (_Rep != nullptr)
		{
			_Rep->_Incwref();
		}
		return *this;
	}
	my_weak_ptr& operator=(my_weak_ptr&& other)
	{
		if (this == &other)return *this;
		if (this->_Rep != nullptr && other._Rep != nullptr && _Rep == other._Rep)
		{
			this->_Rep->_Weaks -= 1;
			other._Rep = nullptr;
			return *this;
		}
		if (_Rep != nullptr && --_Rep->_Weaks == 0)
		{
			delete _Rep;
		}
		_Rep = other._Rep;
		other._Rep = nullptr;
		return *this;
	}
	my_weak_ptr& operator(const my_shared_ptr<_Ty>& other)
	{
		if (_Rep != nullptr && --_Rep->Weaks == 0)
		{
			delete _Rep;
		}
		_Rep = other->_Rep;
		if (_Rep != nullptr)
		{
			_Rep->Incwref();
		}
		return *this;
	}
	my_weak_ptr& operator =(my_shared_ptr<_Ty>&& other) = delete;
	~my_weak_ptr()
	{
		if (_Rep != nullptr && --_Rep->_Weaks == 0)
		{
			delete _Rep;
		}
		_Rep = nullptr;
	}
	bool expired()const
	{
		return this->_Rep->_Uses == 0;
	}
	my_shared_ptr<_Ty>lock()const
	{
		my_shared_ptr<_Ty>_Ret;
		_Ret._Ptr = _Rep->_Ptr;
		_Ret._Rep = _Rep;
		_Ret._Rep->_Incref;
	}
};
#endif

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

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

相关文章

18uec++多人游戏【服务器为两个角色发枪,并能在线开枪】

打开主角类&#xff0c;生成枪的代码逻辑在游戏开始函数里 所以在生成之前&#xff0c;我们需要判断该对象是否在服务器端&#xff08;服务器端视角&#xff09; void ASCharacter::BeginPlay() {Super::BeginPlay();DefaultsFOV CameraComp->FieldOfView;//判断是否在服务…

支付系统 — 支付路由

本文主要介绍下支付中路由系统的主要流程。 支付路由的作用 降低成本&#xff1a;越便宜越好&#xff1b; 提高用户体验&#xff1a;用户支付的越爽越好&#xff1b;越快越好&#xff1b;成功率越高越好。 确保有可用通道&#xff1a;多个选择&#xff0c;确保能完成支付。 …

【JVM】PC程序计数器和PC寄存器

一、JVM体系结构 本文所讲内容主要是 JVM 体系结构图中 运行时数据区 中的 PC寄存器&#xff0c;如下图所示&#xff1a; 二、PC寄存器是什么&#xff1f; 这里引用别人的一句话&#xff1a; 首先这里的PC寄存器并非广义上所指的物理寄存器&#xff0c;或许将其翻译为PC计数…

antd Carousel 重写dot样式

antd的Carousel走马灯组件的dot也就是下面那个滑动的按钮非常的不起眼。 白色背景的时候完全看不到。 但是我们大部分时候又都是白色背景&#xff0c;于是来自己重写一下样式。 在控制台看了一下&#xff0c;应该是这个属性在控制dot的颜色&#xff0c;重写这个属性就可以了。…

Nginx源码解析 --红黑树

预读知识 红黑树是一种自平衡二叉树&#xff0c;不仅可以使用二分法快速查找&#xff0c;而且插入和删除操作的效率也很高&#xff0c;常用于构造关联数组&#xff08;例如C标准库里的set和 map)。 在Nginx里红黑树主要用在事件机制里的定时器&#xff0c;检查连接超时&#…

Debian11之基于kubeadm安装K8S集群

官方安装教程 硬件要求 每台机器的内存要 2GB、CPU2 核心及以上 集群中的所有机器的网络彼此均能相互连接&#xff08;公网和内网都可以&#xff09; 节点之中不可以有重复的主机名、MAC 地址或 product_uuid 开启机器上的某些端口 为了保证 kubelet 正常工作&#xff0c;必须…

FluentCRM 2.6.0:更多功能、集成改进等等!

FluentCRM 2.6.0最新版发布了&#xff0c;它是一个主要的更新版本&#xff0c;为您带来了更多的功能、改进的集成、升级和错误修复&#xff01;让我们来看看 FluentCRM 2.6.0 提供了什么新功能&#xff01; 目录 FluentCRM 2.6的更高级过滤条件 电子邮件活动条件 基于自动化…

STC32G 单片机EEPROM 操作实例

一 STC32G 单片机EEPROM简介 STC32G系列单片机内部集成了大量的EEPROM&#xff0c;特别是STC32G12K128集成多达128K EEPROM。 STC32G内部EEPROM可擦写10万次&#xff0c;分若干扇区&#xff0c;每个扇区512字节。EEPROM的写操作只能将1写为0。要将0写为1&#xff0c;必须擦除…

Hive之函数

Hive之函数 第九章 函数 9.1 系统内置函数 9.1.1 理论 查看内置函数&#xff1a; show functions; 显示函数的详细信息&#xff1a; desc function abs; 显示函数的扩展信息&#xff1a; desc function extended concat; 一、关系运算&#xff1a; 1. 等值比较: 2. 等值…

VSCode:使用CMakeLists.txt构建C++项目

vscode配置 插件&#xff1a; CMake插件主要功能是CMake语法高亮、自动补全CMake Tools的功能主要是结合VSCode IDE使用CMake这个工具&#xff0c;比如生成CMake项目、构建CMake项目等CMake Tools Helper CMake工具本身还是要下载到本地&#xff0c;并且配置环境变量。 项目…

足球二三事 - 世界杯征文

征文活动链接&#xff1a; https://bbs.csdn.net/topics/609601920 从报纸上时候看 1982 年的世界杯&#xff0c;当时我们家里没有电视&#xff0c;晚上的时候听到马路对面的房子里传来惊呼声&#xff0c;也不知道为啥。 1983 年的春节前&#xff0c;家里要打扫房间&#xff…

UE4,UE5虚幻引擎源码版下载

1、进入Epic的GitHub仓库 https://github.com/EpicGames/Signup GitHub - EpicGames/Signup: Information about signing up for a free Epic Games account, and getting access to UnrealEngine source code. 2、加入EpicTeamAdmin 3、进入UnrealEngine仓库 4、找到需要下…

Linux系统中curl命令用法详解

在Linux系统中curl是一个利用URL规则在命令行下工作的文件传输工具&#xff0c;是一款强大的http命令行工具。它支持文件的上传和下载&#xff0c;是综合传输工具。 curl 是常用的命令行工具&#xff0c;用来请求 Web 服务器。它的名字就是客户端&#xff08;client&#xff09…

(C语言)printf打印的字符串太长了,我想分两行!

本文来自于公众号&#xff1a;C语言编程技术分享 一、提问 有下述C程序&#xff1a; #include <stdio.h> #include <stdlib.h>int main() { printf("123456789012345678901234567890\n");system("pause");return 0; } printf函数要打印的字…

tomcat启动配置java_home,启动网址等,点击startup.bat直接启动

自己开发了一个网址&#xff08;基于angular&#xff09;&#xff0c;想共享给别人&#xff0c;直接点击运行&#xff0c;通过tomcat部署网站方式执行。 1、下载tomcat 从官网上下载tomcat&#xff0c;我下载的是tomcat9.0.36,下载完成后&#xff0c;解压&#xff1a; 双击b…

新知实验室

TUIRoom 是一个包含 UI 的开源音视频组件&#xff0c;通过集成 TUIRoom&#xff0c;可以在业务中快速上线音视频房间&#xff0c;屏幕分享&#xff0c;聊天等功能。 项目是开源的项目&#xff0c;根据自己 的需求设计项目。 创建步骤如下 &#xff1a; 一、 开通腾讯云实时…

被裁后一个offer都没有,测试人的问题出在哪里?

裁员潮涌&#xff0c;经济严冬。最近很多测试人过得并不好&#xff0c;行业缩水对测试岗位影响很直接干脆&#xff0c;究其原因还是测试门槛在IT行业较低&#xff0c;同质化测试人员比较多。但实际上成为一位好测试却有着较高的门槛&#xff0c;一名优秀的测试应当对产品的深层…

代码随想录65——额外题目【二叉树】:129求根节点到叶节点数字之和、1382将二叉搜索树变平衡、100相同的树、116填充每个节点的下一个右侧节点指针

文章目录1.129求根节点到叶节点数字之和1.1.题目1.2.解答2.1382将二叉搜索树变平衡2.1.题目2.2.解答3.100相同的树3.1.题目3.2.解答4.116填充每个节点的下一个右侧节点指针4.1.题目4.2.解答4.2.1.递归解法4.2.2.迭代方法1.129求根节点到叶节点数字之和 参考&#xff1a;代码随…

品优购项目详细分析

能够独立完成品优购首页制作哦 能够独立完成品优购列表页制作 能够独立完成品优购注册页制作 能够把品优购网站部署上线 网站制作流程&#xff1a; 初稿审核&#xff1a;网页美工会制作原型图和psd效果图 品优购项目规划&#xff1a; 1 品优购项目整体介绍 描述&#xff1…

【TS】函数重载--可选参数--默认参数

可选参数–默认参数 在ts中定义的数据类型&#xff0c;某些情况下只需要传入定义数据类型的一部分参数&#xff0c;比如&#xff1a;id 、name、age、address&#xff0c;此时需要修改用户的名称&#xff0c;那么只需要传入id、name就够了&#xff1b;某些情况下需要修改用户的…