【C++】————智能指针

 9efbcbc3d25747719da38c01b3fa9b4f.gif

                                                      作者主页:     作者主页

                                                      本篇博客专栏:C++

                                                      创作时间 :2024年8月20日

9efbcbc3d25747719da38c01b3fa9b4f.gif

一,什么是智能指针

在C++中没有垃圾回收机制,必须自己释放分配的内存,否则就会造成内存泄露。解决这个问题最有效的方法是使用智能指针(smart pointer)。智能指针是存储指向动态分配(堆)对象指针的类,用于生存期的控制,能够确保在离开指针所在作用域时,自动地销毁动态分配的对象,防止内存泄露。智能指针的核心实现技术是引用计数,每使用它一次,内部引用计数加1,每析构一次内部的引用计数减1,减为0时,删除所指向的堆内存。

  •  c++中用的最多的是下面三种智能指针

C++11中提供了三种智能指针,使用这些智能指针时需要引用头文件<memory>

  • std::shared_ptr:共享的智能指针
  • std::unique_ptr:独占的智能指针
  • std::weak_ptr:弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的。

二,共享的智能指针shared_ptr

  • 首先了解一下基本概念,再看代码,会学的很快
1. shared_ptr的初始化

 共享智能指针是指多个智能指针可以同时管理同一块有效的内存,共享智能指针shared_ptr 是一个模板类,如果要进行初始化有三种方式:通过构造函数、std::make_shared辅助函数以及reset方法。共享智能指针对象初始化完毕之后就指向了要管理的那块堆内存,如果想要查看当前有多少个智能指针同时管理着这块内存可以使用共享智能指针提供的一个成员函数use_count

2.获取原始指针

 对应基础数据类型来说,通过操作智能指针和操作智能指针管理的内存效果是一样的,可以直接完成数据的读写。但是如果共享智能指针管理的是一个对象,那么就需要取出原始内存的地址再操作,可以调用共享智能指针类提供的get()方法得到原始地址

3. 指定删除器

 当智能指针管理的内存对应的引用计数变为0的时候,这块内存就会被智能指针析构掉了。另外,我们在初始化智能指针的时候也可以自己指定删除动作,这个删除操作对应的函数被称之为删除器这个删除器函数本质是一个回调函数,我们只需要进行实现,其调用是由智能指针完成的。

下面我们来看一下代码如何实现: 

#pragma once
#include <iostream>
#include <functional>namespace zy
{template<class T>class shared_ptr{public:shared_ptr(T* ptr = nullptr) : _ptr(ptr), _pcount(ptr ? new int(1) : nullptr){std::cout << "shared_ptr(T* ptr)" << std::endl;}template<class D>shared_ptr(T* ptr = nullptr,D del): _ptr(ptr), _pcount(ptr ? new int(1) : nullptr), _del(del){}shared_ptr(const shared_ptr& sp) : _ptr(sp._ptr), _pcount(sp._pcount){++(*_pcount);std::cout << "Copy constructor" << std::endl;}shared_ptr& operator=(const shared_ptr& sp){if (this != &sp){// 释放当前对象管理的资源(如果有)this->Realease();_ptr = sp._ptr;_pcount = sp._pcount;++(*_pcount);}return *this;}~shared_ptr(){Realease();}void Realease(){if (_pcount && --(*_pcount) == 0){//delete _ptr;_del(_ptr);delete _pcount;_ptr = nullptr;_pcount = nullptr;}}T* get(){return _ptr;}int use_count(){return _pcount ? *_pcount : 0;}T& operator*() { return *_ptr; }T* operator->() { return _ptr; }private:T* _ptr;int* _pcount;fuction<void(T* ptr)>_del = [](T* ptr) {delete ptr};};
}

 三,独占的智能指针unique_ptr

 1. 初始化

std::unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针,可以通过它的构造函数初始化一个独占智能指针对象,但是不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr。

 2. 删除器

 unique_ptr指定删除器和shared_ptr指定删除器是有区别的,unique_ptr指定删除器的时候需要确定删除器的类型,所以不能像shared_ptr那样直接指定删除器

#pragma once
#include <iostream>template <typename T>
class unique_ptr {
public:// 构造函数,接受一个原始指针并接管其所有权unique_ptr(T* ptr = nullptr) : ptr_(ptr) {}// 移动构造函数,转移所有权unique_ptr(unique_ptr&& other) noexcept : ptr_(other.ptr_) {other.ptr_ = nullptr;}// 移动赋值运算符,转移所有权unique_ptr& operator=(unique_ptr&& other) noexcept {if (this!= &other) {reset();ptr_ = other.ptr_;other.ptr_ = nullptr;}return *this;}// 析构函数,释放所管理的资源~unique_ptr() {reset();}// 解引用操作符T& operator*() const {return *ptr_;}// 箭头操作符T* operator->() const {return ptr_;}// 获取原始指针T* get() const {return ptr_;}// 释放所管理的资源并将指针置为 nullptrvoid reset(T* ptr = nullptr) {if (ptr_) {delete ptr_;}ptr_ = ptr;}private:T* ptr_;
};

四, 弱引用的智能指针weak_ptr

 弱引用智能指针std::weak_ptr可以看做是shared_ptr的助手,它不管理shared_ptr内部的指针。std::weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr中管理的资源是否存在。

 1 初始化

 弱引用智能指针std::weak_ptr可以看做是shared_ptr的助手,它不管理shared_ptr内部的指针。std::weak_ptr没有重载操作符*和->,因为它不共享指针,不能操作资源,所以它的构造不会增加引用计数,析构也不会减少引用计数,它的主要作用就是作为一个旁观者监视shared_ptr中管理的资源是否存在。

#include <iostream>
#include <memory>
using namespace std;int main() 
{shared_ptr<int> sp(new int);weak_ptr<int> wp1;weak_ptr<int> wp2(wp1);weak_ptr<int> wp3(sp);weak_ptr<int> wp4;wp4 = sp;weak_ptr<int> wp5;wp5 = wp3;return 0;
}
  1. weak_ptr<int> wp1;构造了一个空weak_ptr对象
  2. weak_ptr<int> wp2(wp1);通过一个空weak_ptr对象构造了另一个空weak_ptr对象
  3. weak_ptr<int> wp3(sp);通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象
  4. wp4 = sp;通过一个shared_ptr对象构造了一个可用的weak_ptr实例对象(这是一个隐式类型转换)
  5. wp5 = wp3;通过一个weak_ptr对象构造了一个可用的weak_ptr实例对象
  •  通过调用std::weak_ptr类提供的use_count()方法可以获得当前所观测资源的引用计数
 2.常用函数

通过调用std::weak_ptr类提供的expired()方法来判断观测的资源是否已经被释放
通过调用std::weak_ptr类提供的lock()方法来获取管理所监测资源的shared_ptr对象
通过调用std::weak_ptr类提供的reset()方法来清空对象,使其不监测任何资源

  • 利用weak_ptr可以解决shared_ptr的一些问题
  1.  返回管理this的shared_ptr
  2. 解决循环引用问题

最后:

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.一个冷知识:
屏蔽力是一个人最顶级的能力,任何消耗你的人和事,多看一眼都是你的不对。

2.你不用变得很外向,内向挺好的,但需要你发言的时候,一定要勇敢。
正所谓:君子可内敛不可懦弱,面不公可起而论之。

3.成年人的世界,只筛选,不教育。

4.自律不是6点起床,7点准时学习,而是不管别人怎么说怎么看,你也会坚持去做,绝不打乱自己的节奏,是一种自我的恒心。

5.你开始炫耀自己,往往都是灾难的开始,就像老子在《道德经》里写到:光而不耀,静水流深。

最后如果觉得我写的还不错,请不要忘记点赞✌,收藏✌,加关注✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚菜鸟逐渐成为大佬。加油,为自己点赞!

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

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

相关文章

标准版v5.4安卓手机小程序扫码核销读取不到核销码的问题

修改这个文件&#xff0c;红色的那块代码替换成绿色的这段代码&#xff0c;然后重新打包上传。 文件地址&#xff1a;template/uni-app/pages/admin/order_cancellation/index.vue let path decodeURIComponent(res.path); self.verify_code path.split(‘code’)[1]; h5…

使用Element UI组件时,icon图标不显示

问题描述&#xff1a; 我在使用Element UI组件的日期选择器时&#xff0c;发现图标不显示(左边是原图&#xff0c;右边的问题图)。 经过检查我发现&#xff0c;我的JS&#xff0c;CSS文件都没有问题&#xff0c;只是缺少了element-icons.tff和element-icons.woff这两个文件。 …

C语言之“ 数组 ”

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;C语言基础 目录 前言 一、数组 二、一维数组 2.1 一维数组的创建和初始化 数组创建 数组初始化 数组类型 2.2 一维数组的使用 数组下标 数组打印 数组输…

SIRA-PCR: Sim-to-Real Adaptation for 3D Point Cloud Registration 论文解读

目录 一、导言 二、 相关工作 1、三维点云配准工作 2、无监督域适应 三、SIRA-PCR 1、FlyingShape数据集 2、Sim-to-real自适应方法 3、配准 4、损失函数 一、导言 该论文来自于ICCV2023&#xff0c;论文提出了一种新的方法SIRA-PCR&#xff0c;通过利用合成数据Flying…

Java面试--框架--Spring MVC

Spring MVC 目录 Spring MVC1.spring mvc简介2.spring mvc实现原理2.1核心组件2.2工作流程 3.RESTful 风格4.Cookie&#xff0c;Session4.1 会话4.2 保存会话的两种技术 5.拦截器5.1过滤器、监听器、拦截器的对比5.2 过滤器的实现5.3 拦截器基本概念5.4 拦截器的实现 1.spring …

Ropdump:针对二进制可执行文件的安全检测工具

关于Ropdump Ropdump是一款针对二进制可执行文件的安全检测工具&#xff0c;该工具基于纯Python开发&#xff0c;是一个命令行工具&#xff0c;旨在帮助广大研究人员检测和分析二进制可执行文件中潜在的ROP小工具、缓冲区溢出漏洞和内存泄漏等安全问题。 功能介绍 1、识别二进…

使用gpreftools测试性能

参考文献&#xff1a; C 性能分析工具调研_性能分析工具 gperf perf vergi 比较-CSDN博客性能测试工具CPU profiler(gperftools)的使用心得-CSDN博客gperftools使用方法和常见问题_pprof no nodes to print-CSDN博客c 分析 gperftools 总结 | Weakyon Blog 文章目录 安装使用 …

第2章-01-网站中的资源介绍

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲。 🎉欢迎 👍点赞✍评论⭐收…

微信小程序--30(网络数据请求)

1.小程序中网络数据请求的限制 只能请求HTTPS类型的接口必须将接口的域名添加到信任列表中 2.配置request合法域名 需求描述 希望请求某个域名下的接口 步骤 登录小程序管理后台→开发→开发设置→服务器域名→修改request合法域名 练习 注意事项 域…

【Linux】yum、vim、gcc/g++的使用

目录 一、Linux 软件包管理器 yum 什么是软件包 关于 rzsz 查看软件包★ 如何安装软件★ 如何卸载软件★ Linux 开发工具 二、Linux编译器-vim使用 vim的基本概念 vim的基本操作 vim正常模式命令集 vim末行模式命令集 vim操作总结 如果在vim界面不小心按了Ctrl …

Unity的粒子系统

目录 基础参数与模块 创建与编辑 功能与应用 实例与教程 结论 Unity粒子系统的最新功能和更新有哪些&#xff1f; 如何在Unity中使用Visual Effect Graph创建复杂粒子效果&#xff1f; Unity粒子系统的高级应用技巧有哪些&#xff1f; 在Unity中实现粒子系统时的性能优…

【计算机组成原理】二、数据的表示和运算:1.数值与编码(十进制二进制转换、BCD码、ASCII码、汉字编码、奇偶校验码、循环冗余检测CRC、海明码)

二、数据的表示和运算 文章目录 二、数据的表示和运算1.数值与编码1.1数据存储和排列❗1.2十进制转换1.2.1整数1.2.2小数 1.3二进制转换1.3.1 B->O1.3.2 B->H 1.4真值&机器数1.5 BCD码1.6 ASCII码1.7汉字与GBK1.8 UTF1.9检错码1.9.1奇偶校验码1.9.2循环冗余检测CRC1.…

CentOS7设置默认免密登录用户root

CentOS7设置默认免密登录用户root 步骤1、打开要更改的 CentOS 系统2、切换到root用户2、reboot重启系统 步骤 1、打开要更改的 CentOS 系统 2、切换到root用户 2、reboot重启系统

如何基于AI大模型来做数据治理?

在数字化时代的浪潮中&#xff0c;数据治理已成为企业管理的核心议题。随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;尤其是大型语言模型&#xff08;如GPT-4&#xff09;的涌现&#xff0c;AI大模型在数据治理中的应用正逐渐成为一种创新且有效的解决方案…

LLM才硬件(显存)需求

参考&#xff1a; https://www.hardware-corner.net/guides/computer-to-run-llama-ai-model/ GitHub - hiyouga/LLaMA-Factory: Efficiently Fine-Tune 100 LLMs in WebUI (ACL 2024) 直观的一个表&#xff1a;

利用队列收集单双击和长按按键

利用队列收集单双击和长按按键 引言 当我们仅仅通过在while循环里面进行判断按键类型的标志位, 然后进行操作的时候, 我们的最小例程很小, 所以能够实时的检测到按键,从而触发实验现象. 假如我们此时进入了一个事件处理函数呢 ? 并且这个这个函数的操作是不可被打断的, 如果此…

修改Docker的默认网段

1、确认修改前docker网段 [rootkfk12 ~]# ifconfig docker0 2、修改docker配置设置网段 [rootkfk12 ~]# cat > /etc/docker/daemon.json << EOF{ "registry-mirrors": [ "https://vh3bm52y.mirror.aliyuncs.com", "https://regi…

C:每日一题:字符串左旋

题目&#xff1a;实现一个函数&#xff0c;可以实现字符串的左旋 例如&#xff1a;ABCD左旋一个字符就是BCDA&#xff1b;ABCD左旋两个字符就是CDAB&#xff1b; 1、解题思路&#xff1a; 1.确定目标旋转k个字符&#xff0c;我们要获取字符串的长度 len&#xff0c;目的是根…

PyCharm单步调试

1、先在入口设置断点&#xff0c;再点击爬虫图标&#xff08;shift F9&#xff09;开始调试 调试图标如图&#xff1a; 2、蓝色光标表示当前运行在这行 3、快捷键 F7&#xff1a;进入当前行函数 F8&#xff1a;单步 F9&#xff1a;全速运行

Nuclei文件上传小Tips

前言 Nuclei对于文件上传类型Poc编写小Tips 平台 ProjectDiscovery Cloud Platform: https://cloud.projectdiscovery.io/ JsonPath: https://jsonpath.com/ Json解析&#xff1a; 在线json解析平台即可 案例 某康resourceOperations upload接口存在前台上传 具体接口&…