智能指针——浅析

智能指针

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

介绍及作用

在异常产生进行跳转时,通过栈帧回收进行内存释放,防止内存泄漏
基于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——如果在这个指针是拷贝构造生成的,那还得进行包装器拷贝,同样在赋值重载的地方也需要同样的操作,还不如声明的时候给默认值

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

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

相关文章

CS144--Chapter0--wsl2+docker环境搭建

我的笔记本配置 荣耀magicbook16&#xff0c;容量是500G&#xff0c;芯片是R7-5800 由于笔记本容量较小&#xff0c;因此考虑这个方案&#xff0c;对于台式机用户&#xff0c;建议可以直接用虚拟机或者双系统。 前言 斯坦福官网给出的方法是用他们的镜像&#xff08;基于Ubu…

linux中常用的命令

一&#xff1a;tree命令 &#xff08;码字不易&#xff0c;关注一下吧&#xff0c;w~~w) 以树状形式查看指定目录内容。 tree --树状显示当前目录下的文件信息。 tree 目录 --树状显示指定目录下的文件信息。 注意&#xff1a; tree只能查看目录内容&#xff0c;不能…

【大厂AI课学习笔记】1.3 人工智能产业发展(2)

&#xff08;注&#xff1a;腾讯AI课学习笔记。&#xff09; 1.3.1 需求侧 转型需求&#xff1a;人口红利转化为创新红利。 场景丰富&#xff1a;超大规模且多样的应用场景。主要是我们的场景大&#xff0c;数据资源丰富。 抗疫加速&#xff1a;疫情常态化&#xff0c;催生新…

嵌入式学习第十四天!(结构体、共用体、枚举、位运算)

1. 结构体&#xff1a; 1. 结构体类型定义&#xff1a; 嵌入式学习第十三天&#xff01;&#xff08;const指针、函数指针和指针函数、构造数据类型&#xff09;-CSDN博客 2. 结构体变量的定义&#xff1a; 嵌入式学习第十三天&#xff01;&#xff08;const指针、函数指针和…

Pytorch学习01_加载数据初认识

一.Dataset 新建py文件 from torch.utils.data import Dataset可以按住”Ctrl“,鼠标左键点击Dataset&#xff0c;可以打开Dataset的定义及其内部函数 二.编写 引用cv2模块 终端运行 pip install opencv-python 然后就可以引用cv2模块 import cv2 引用Image from PIL import…

React中封装大屏自适应(拉伸)仿照 vue2-scale-box

0、前言 仿照 vue2-scale-box 1、调用示例 <ScreenAutoBox width{1920} height{1080} flat{true}>{/* xxx代码 */}</ScreenAutoBox> 2、组件代码 import { CSSProperties, ReactNode, RefObject, useEffect, useRef, useState } from react//数据大屏自适应函数…

Leetcode1109. 航班预订统计

Every day a Leetcode 题目来源&#xff1a;1109. 航班预订统计 解法1&#xff1a;差分数组 注意到一个预订记录实际上代表了一个区间的增量。我们的任务是将这些增量叠加得到答案。因此&#xff0c;我们可以使用差分解决本题。 代码&#xff1a; /** lc appleetcode.cn i…

Altium Designer的学习

PCB设计流程 1.新建空白工程&#xff1a; 创建一个新的工程 新建四个文件&#xff0c;并且保存&#xff1a; 每次打开文件时&#xff0c;打开以.PrjPcb结尾的文件 2.元件符号的创建&#xff1a; 在绘制图形的时候设置成10mil,为了在原理图中显得不那么大。 在绘制引脚的时候设…

贪吃蛇---C语言---详解

引言 C语言已经学了不短的时间的&#xff0c;这期间已经开始C和Python的学习&#xff0c;想给我的C语言收个尾&#xff0c;想起了小时候见过别人的老人机上的贪吃蛇游戏&#xff0c;自己父母的手机又没有这个游戏&#xff0c;当时成为了我的一大遗憾&#xff0c;这两天发现C语…

MBR分区转换为GPT分区

这里有一个ecs-test用于测试MBR转换为GPT 新增一块数据盘 将数据盘以MBR分区格式分区 将整块磁盘以mbr形式分区 格式化&#xff0c;挂载等 上传文件&#xff0c;方便测试(以便后续转换格式类型&#xff0c;防止文件丢失) 取消挂载 将MBR转换为GPT 需先下载gdisk yum instal…

K8S网络

一、介绍 k8s不提供网络通信&#xff0c;提供了CNI接口(Container Network Interface&#xff0c;容器网络接口)&#xff0c;由CNI插件实现完成。 1.1 Pod通信 1.1.1 同一节点Pod通信 Pod通过虚拟Ethernet接口对&#xff08;Veth Pair&#xff09;与外部通信&#xff0c;Veth…

理想架构的高回退Doherty功率放大器理论与ADS仿真-Multistage

理想架构的高回退Doherty功率放大器理论与仿真-Multistage 参考&#xff1a; 三路Doherty设计 01 射频基础知识–基础概念 Switchmode RF and Microwave Power Amplifiers、 理想架构的Doherty功率放大器&#xff08;等分经典款&#xff09;的理论与ADS电流源仿真参考&#x…