当前位置: 首页 > news >正文

智能指针——浅析

智能指针

本人不才,只能将智能指针介绍一下,无法结合线程进行深入探索

介绍及作用

在异常产生进行跳转时,通过栈帧回收进行内存释放,防止内存泄漏
基于RAII思想可以创建出只能指针
RAII(Resource Acquisition Is Initialization)——是一种利用对象控制空间生命周期的技术
这种技术好处就在于可以自动化的释放资源
智能指针——使用如指针,支持->和**针对内置数据类型->针对自定义数据类型


先介绍一个对象管理一份资源

auto_ptr
	template<class T>class auto_ptr{// auto_ptr 会产生指针悬空的情况,在进行解引用的时候很危险public:auto_ptr(T* p=nullptr) :_ptr(p) {}~auto_ptr(){puts("~auto_ptr()");delete _ptr;}auto_ptr(auto_ptr<T>& p){_ptr = p._ptr;p._ptr = nullptr;}auto_ptr<T>& operator=(auto_ptr<T>& p){// 因为是一个对象管理一份资源,比较的时候也可以使用this!=&pif (_ptr != p._ptr){if (_ptr) delete _ptr;_ptr = p._ptr;p._ptr = nullptr;}return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};

auto_ptr会在赋值的时候将资源进行转移,并将自己置为nullptr,从而造成指针悬空的问题

unique_ptr
	template<class T>class unique_ptr{// 在auto_ptr的基础上进行优化,防拷贝public:unique_ptr(T* p = nullptr) :_ptr(p) {}~unique_ptr(){puts("~auto_ptr()");delete _ptr;}unique_ptr(const unique_ptr<T>& p) = delete;unique_ptr& operator=(const unique_ptr<T>& p) = delete;T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:// unique_ptr(const unique_ptr<T>& p);// unique_ptr& operator=(const unique_ptr<T>& p);T* _ptr;};

只是为了解决拷贝带来的指针悬空的问题——禁用拷贝构造和赋值重载
两种方式达到禁用拷贝构造和赋值重载

  1. 将拷贝构造和赋值重载定义成private
  2. 由于C++11扩展了delete的功能,可以在public中对两个函数使用delete关键字修饰

多个指针同时享有一份资源

shared_ptr

使用一个计数指针进行计数
我的代码写成这个样子是因为考虑到可能只声明指针但是没有赋值的情况,所以就需要对指针位nullptr的情况进行特殊判断

struct ListNode
{int val;bit::shared_ptr<ListNode> next;bit::shared_ptr<ListNode> prev;~ListNode(){cout << "~ListNode()" << endl;}
};template<class T>class shared_ptr	{// 删除器就是为了解决:释放数组,不是new出来的指针public:shared_ptr(T* p = nullptr) :_ptr(p), _count(new int(0)) {}template<class D>shared_ptr(T* p,D del):_ptr(p),_count(new int(1)),_del(del){if (p) (*_count)++;}~shared_ptr(){if (_ptr){//printf("~shared_ptr() -> %p\n", _ptr);if (--(*_count) == 0){delete _count;}delete _ptr;}if (_ptr == nullptr) delete _count;}shared_ptr(const shared_ptr<T>& p){if (_ptr && _ptr != p._ptr){if (--(*_count) == 0) _count = p._count;(*_count)++;_ptr = p._ptr;}else{// nullptr / 有值相等_ptr = p._ptr;_count = p._count;//*_count++; // ++优先级大于*,最好不要写这种代码(*_count)++;}}shared_ptr& operator=(const shared_ptr<T>& p){if (_ptr && _ptr != p._ptr){if (--(*_count) == 0) _count = p._count;(*_count)++;_ptr = p._ptr;}else{// nullptr / 有值相等_ptr = p._ptr;_count = p._count;(*_count)++;}return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}int use_count() const {return *_count;}T* get() const{return _ptr;}private:T* _ptr;int* _count;// 引入计数指针function<void(T*)> _del = [](T* p) {delete p; };};

在这里插入图片描述
这里会产生循环引用的问题
请添加图片描述
为了解决这个问题有了weak_ptr


weak_ptr

weak_ptr只进行引用不进行计数

struct ListNode
{int val;bit::weak_ptr<ListNode> next;bit::weak_ptr<ListNode> prev;~ListNode(){cout << "~ListNode()" << endl;}
};template<class T>class weak_ptr{// 不增加引用计数public:weak_ptr() :_ptr(nullptr) {}~weak_ptr(){//printf("~shared_ptr() -> %p\n", _ptr);}weak_ptr(const shared_ptr<T>& p){_ptr = p.get();}weak_ptr& operator=(const shared_ptr<T>& p){_ptr = p.get();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};

在这里插入图片描述


使用包装器进行释放

这里还有一个问题——如何根据空间开的个数进行释放呢,数组和指针释放的方式是不一样的
也就是在share_ptr看不懂的版本

template<class T>
struct Del
{void operator()(T* ptr){delete[] ptr;}
};template<class T>class shared_ptr	{// 删除器就是为了解决:释放数组,不是new出来的指针public:shared_ptr(T* p = nullptr) :_ptr(p), _count(new int(0)) {}template<class D>shared_ptr(T* p,D del):_ptr(p),_count(new int(1)),_del(del){if (p) (*_count)++;}~shared_ptr(){if (_ptr){//printf("~shared_ptr() -> %p\n", _ptr);if (--(*_count) == 0){delete _count;}delete _ptr;}if (_ptr == nullptr) delete _count;}shared_ptr(const shared_ptr<T>& p){if (_ptr && _ptr != p._ptr){if (--(*_count) == 0) _count = p._count;(*_count)++;_ptr = p._ptr;}else{// nullptr / 有值相等_ptr = p._ptr;_count = p._count;//*_count++; // ++优先级大于*,最好不要写这种代码(*_count)++;}}shared_ptr& operator=(const shared_ptr<T>& p){if (_ptr && _ptr != p._ptr){if (--(*_count) == 0) _count = p._count;(*_count)++;_ptr = p._ptr;}else{// nullptr / 有值相等_ptr = p._ptr;_count = p._count;(*_count)++;}return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}int use_count() const {return *_count;}T* get() const{return _ptr;}private:T* _ptr;int* _count;// 引入计数指针function<void(T*)> _del = [](T* p) {delete p; };};

仿函数,函数指针,lambda可以使用包装器——不论使用哪一种,实现的目的就是为了释放数组
他的类型一定是void(*T)
为什么需要在声明的时候就给默认到lambda——如果在这个指针是拷贝构造生成的,那还得进行包装器拷贝,同样在赋值重载的地方也需要同样的操作,还不如声明的时候给默认值

相关文章:

  • 如何发布自己的npm包:
  • 用两个队列实现栈
  • Day 17------C语言收尾之链表的删除、位运算、预处理、宏定义
  • 开源模型应用落地-业务优化篇(三)
  • logback日志配置
  • mongodb数据库集合(表)的创建和数据修改
  • 虹科技术|一文详解IO-Link Wireless技术如何影响工业无线自动化
  • MySQL分区的优缺点
  • 分类预测 | Matlab实现GAF-PCNN-MATT格拉姆角场和双通道PCNN融合多头注意力机制的分类预测/故障识别
  • 力扣热门100题刷题笔记 - 10. 正则表达式匹配
  • C语言顺序表
  • 【图论】基环树
  • 16.docker删除redis缓存数据、redis常用基本命令
  • 关于Linux和消息队列常见的十道面试题
  • 如何使用VS Code编写小游戏并实现公网游玩本地游戏【内网穿透】
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • android百种动画侧滑库、步骤视图、TextView效果、社交、搜房、K线图等源码
  • CentOS 7 防火墙操作
  • If…else
  • JavaScript 基础知识 - 入门篇(一)
  • JavaScript实现分页效果
  • java取消线程实例
  • Java应用性能调优
  • Terraform入门 - 1. 安装Terraform
  • WePY 在小程序性能调优上做出的探究
  • XForms - 更强大的Form
  • 仿天猫超市收藏抛物线动画工具库
  • 分布式熔断降级平台aegis
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 我的zsh配置, 2019最新方案
  • 写代码的正确姿势
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • #{}和${}的区别?
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (pojstep1.1.2)2654(直叙式模拟)
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (编译到47%失败)to be deleted
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (三) prometheus + grafana + alertmanager 配置Redis监控
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (转)大道至简,职场上做人做事做管理
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET企业级应用架构设计系列之应用服务器
  • []C/C++读取串口接收到的数据程序
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [C++]C++基础知识概述
  • [CF]Codeforces Round #551 (Div. 2)
  • [codevs 1288] 埃及分数 [IDdfs 迭代加深搜索 ]
  • [Docker]五.Docker中Dockerfile详解