智能指针详解

目录

智能指针原理

RAII

Unique_ptr

Shared_ptr

Shared_ptr缺点

定制删除器


     在C++库里提供的智能指针有跟多,如下图所示,使用时需要包含头文件<memory>。下面将详细介绍这些智能指针的底层原理和缺点,还有每个智能指针的应用场景。

智能指针原理

RAII

        RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。

        在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法的好处在于:

  1.         1、不需要显式地释放资源。
  2.         2、采用这种方式,对象所需的资源在其生命期内始终保持有效。

        智能指针的思想就是上述RAII的技术。智能指针雏形就相当于把一个指针存储在一个类中,当这个类的生命周期结束时,会调用它的析构函数,在析构函数中我们去释放这个指针所指向的空间,这样就避免了我们new了空间忘记delete。

        在这个类内,我们可以进行运算符重载,把operator*、operator->、operator[]都重载上,这样才实现了一个完整的指针的效果。

        上述这些指针的使用效果都很容易实现,最难的部分是智能指针的拷贝,如果我们拷贝了一个智能指针,这两个智能指针会管理同块区域,当两个智能指针析构时,会调用两次析构函数,也就是释放两次空间,正常情况下这样是会报错的。

        在C++98版本的auto_ptr底层为了实现智能指针的拷贝构造,它会把被拷贝的智能指针的管理权转移到拷贝的智能指针,原智能指针置空。如下图所示:

        显然,C++98这个设计是失败的,被拷贝的智能指针(上图sp1)被置空了,不能再次使用。

        所以在C++11的智能指针(unique_ptr)进行了优化。在unique_ptr中直接明确规定不允许拷贝构造,这在auto_ptr中是没有规定的。

Unique_ptr

        Unique_prt的定义中直接规定了没有拷贝构造,同理也没有赋值重载。

        使用unique_ptr创建数组指针时,模板传参也必须是:类型[],要不然编译器只会析构一次,不会析构整个数组(数组要析构多次)shared_ptr使用方法也一样。

        unique_ptr没有不允许拷贝,这也是有缺陷的,一个能正常使用的指针就是可以进行拷贝的,后续在share_ptr中对此进行了优化

Shared_ptr

        Shared_ptr允许拷贝构造和赋值重载。它在底层加入一个引用计数,即当有几个智能指针同时指向这个空间时,引用计数便是几。在析构时,先减少引用计数,直到引用计数为1时,才调用delete去释放空间。所以shared_ptr有一个函数,名为:use_count可以返回引用计数是多少。

        也是因为Shared_ptr允许赋值重载,所以有有一种新的方法来创建智能指针(unique_ptr和auto_ptr都没有)

Shared_ptr缺点

        Shared_ptr不支持循环引用,循环引用是指,我(p1)的成员中有智能指针指向(管理)你(p2),你(p2)的成员中有智能指针指向(管理)我,这样会使我(p1)和你(p2)的引用计数都变成2,在析构的时候就和相互影响,导致析构失败,出现内存泄漏,具体情况如下图所示:

        为了解决shared_ptr的缺陷,C++有新加入了一个智能指针weak_ptr,但weak_ptr本质上不算智能指针,它不支持RAII,不能单独管理资源(引用计数不增加),它专门来解决上述shared_ptr的循环引用

        将类内的成员智能指针改为weak_ptr就可以正常使用了(外面还是share_ptr

        weakl_ptr的底层解决方法就是,当我们对智能指针循环引用时,不增加内部的引用计数。

        Weak_ptr还有一个特殊的成员函数,expired,这个成员函数能够返回它指向的资源是否还存在(有没有被释放)。返回1代表资源已经被释放,0则相反。

定制删除器

        当我们使用shared_ptr去封装指针时,由于share_ptr的析构函数默认调用的是delete函数,所以只能对new和new[]成立,对于其他情况开辟的空间,比如以下两种情况:malloc和fopen,shared_ptr原本自带的析构函数,都不能很好的释放空间,甚至对于fopen甚至会报错,这时我们就需要针对不同的指针情况定制删除器。

        Shared_ptr的底层也是支持传递定制删除器的,如上图所示,D del可以接收仿函数,上述不能正常析构的部分,加上下图析构函数

        写完定制删除器后,在构建对象的时候传递,后面就可以正常析构了。

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

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

相关文章

嘉立创EDA中PCB快速画螺旋触摸焊盘或其他不规则形状

常见触摸焊盘 首先需要有CAD软件 使用CAD的原因&#xff1a;能快速编辑线条和不规则形状&#xff0c;在嘉立创EDA中不能快速完成。 画图整体步骤&#xff1a; 1&#xff0c;先在CAD中画出螺旋线&#xff08;HELIX&#xff09; 这里需要设置底部半径&#xff0c;圈数和顶部半…

【MYSQL】mysql约束---自增长约束(auto_increment)

1、概念 在Mysql中&#xff0c;当主键为自增长后&#xff0c;这个主键的值就不再需要用户输入数据了&#xff0c;而由数据库系统根据定义自动赋值。每增加一条记录&#xff0c;主键会自动以相同的步长进行增长。 注意&#xff1a;自增长约束通常与主键放在一起使用。 通过给…

网盘能否作为FTP替代产品?企业该如何进行FTP国产化替代?

近年来&#xff0c;信创的概念引入和高效实践落地让更多的行业企业自发性地进行国产化替代&#xff0c;目前信创国产化替代还多发生在操作系统和应用层面&#xff0c;软件工具等目前还在下一阶段规划&#xff0c;但很多企业未雨绸缪&#xff0c;已经在做调研和尝试。 FTP作为世…

codetop标签双指针题目大全解析(三),双指针刷穿地心!!!!!

复习比学习更重要&#xff0c;更需要投入时间&#xff0c;更需要花费精力 1.字符串的排列2.找出字符串中第一个匹配的下标3.最大连续1的个数II4.数组中的山脉5.移除元素6.两个数组的交集II7.有序数组的平方8.删除有序数组中的重复项II9.寻找重复数10.水果成篮 1.字符串的排列 …

【黑马点评】使用RabbitMQ实现消息队列——3.使用Jmeter压力测试,导入批量token,测试异步秒杀下单

3 批量获取用户token&#xff0c;使用jmeter压力测试 3 批量获取用户token&#xff0c;使用jmeter压力测试3.1 需求3.2 实现3.2.1 环境配置3.2.2 修改登录接口UserController和实现类3.2.3 测试类 3.3 使用jmeter进行测试3.4 测试结果3.5 将用户登录逻辑修改回去 3 批量获取用户…

前端练习小项目 —— 让图片变得更 “色”

前言&#xff1a;相信读者在学习完了HTML、CSS和JavaScript之后已经想要迫不及待的想找一个小型的项目来练练手&#xff0c;那么这篇文章就正好能满足你的 “需求”。 ✨✨✨这里是秋刀鱼不做梦的BLOG ✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客 在开始学习…

基于springboot+小程序的智慧物业平台管理系统(物业1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 智慧物业平台管理系统按照操作主体分为管理员和用户。 1、管理员的功能包括报修管理、投诉管理管理、车位管理、车位订单管理、字典管理、房屋管理、公告管理、缴费管理、维修指派管理、…

Mysql(六) --- 聚合函数,分组和联合查询

文章目录 前言1.聚合函数1.1.常用的函数1.2.COUNT()1.3.SUM()1.4.AVG()1.5.MIN()、MAX() 2.GROUP BY 分组查询2.1.语法2.2.示例2.3.HAVING 子句 3.联合查询3.1.为什么要进行联合查询3.2.那么是如何进行联合查询的3.3.示例&#xff1a;一个完整的联合查询的过程3.4.内连接3.5.外…

C++(异常)

目录 C语言传统的处理错误的方式 传统的错误处理机制 C异常概念 异常的使用 异常的抛出和捕获 异常的抛出和匹配原则 在函数调用链中异常栈展开匹配原则 异常的重新抛出 异常安全 异常规范 自定义异常体系 C标准库的异常体系 异常的优缺点 C异常的优点 C异常的缺…

「自动化测试」Selenium 的使用

使用 Selenium 需要先导入相关依赖 <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>4.0.0</version> </dependency><dependency><groupId>io.gith…

【M365运维】在SPO文档库里删除文档时,遇到文档被签出无法删除。

【问题】SPO的存储空间剩的不多了&#xff0c;在清理文档库时&#xff0c;遇到有些文档被签出但用户已经离职&#xff0c;删除文件时报错。 【解决】翻SPO的设置时&#xff0c;看到有“管理没有已签入版本的文件”&#xff0c;在里面获取文件的所有权之后就可以删除了。 具体…

【树莓派5B】IO串口通信使用

超级简单的串口使用 前言零、检查准备&#xff08;可略&#xff09;0.1 查看UART引脚&#xff1a;0.2 扩展一下引脚查看的方法 一、配置准备1.1 检查端口配置1.2 查看串口映射1.3 下载minicom串口调试工具1.4 通过命令获取串口上的数据 二、python的serial进行收发测试总结 前言…

sqli-labs靶场第二关less-2

sqli-labs靶场第二关less-2 本次测试在虚拟机搭建靶场&#xff0c;从主机测试 1、输入?id1和?id2发现有不同的页面回显 2、判断注入类型 http://192.168.128.3/sq/Less-2/?id1’ 从回显判断多一个‘ &#xff0c;预测可能是数字型注入 输入 http://192.168.128.3/sq/Less…

Study-Oracle-10-ORALCE19C-RAC集群维护

一路走来,所有遇到的人,帮助过我的、伤害过我的都是朋友,没有一个是敌人。 一、RAC的逻辑架构与进程 1、RAC 与单实例进程的对比 2、RAC相关进程功能 3、在主机查看RAC后台进程 快捷键设置 alias sqlplus=rlwrap sqlplus alias rman=rlwrap rman alias crsctl=/u01/app…

使用springCache实现缓存

简介 这个springCache貌似jdk8或者以上才可以 cache最好加在controller层&#xff0c;毕竟返回给前端的数据&#xff0c;在这一步才是最完整的&#xff0c;缓存controller的数据才有意义 配置 导入依赖 <dependency><groupId>org.springframework.boot</groupId…

基于Python的美术馆预约系统【附源码】

效果如下&#xff1a; 系统首页界面 系统注册页面 美术馆详细页面 公告信息详细页面 后台登录界面 管理员主界面 美术馆管理界面 预约参观管理界面 研究背景 随着文化娱乐活动的日益丰富&#xff0c;美术馆作为展示艺术作品、传播文化的重要场所&#xff0c;其管理和服务模式…

go语言protoc的详细用法与例子

一. 原来的项目结构 二. 选择源proto文件及其目录&目的proto文件及其目录 在E:\code\go_test\simple_demo\api 文件夹下&#xff0c;递归创建\snapshot\helloworld\v1\ad.pb.go E:\code\go_test\simple_demo> protoc --go_outpathssource_relative:./api .\snapshot\h…

Dolma:包含三万亿Token的语言模型预训练研究开放语料库

前言 原论文&#xff1a;Dolma: an Open Corpus of Three Trillion Tokens for Language Model Pretraining Research 摘要 关于训练当前最佳性能语言模型的预训练语料库的信息很少被讨论——商业模型很少详细说明它们的数据&#xff0c;即使是开源模型也往往在没有训练数据…

Ubuntu开机进入紧急模式处理

文章目录 Ubuntu开机进入紧急模式处理一、问题描述二、解决办法参考 Ubuntu开机进入紧急模式处理 一、问题描述 Ubuntu开机不能够正常启动&#xff0c;自动进入紧急模式&#xff08;You are in emergency mode&#xff09;。具体如下所示&#xff1a; 二、解决办法 按CtrlD进…