智能指针详解

目录

智能指针原理

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,一经查实,立即删除!

相关文章

AI寒冬?不,2025年将是AI代理之年

引言 近年来,人工智能(AI)的发展速度令人瞩目,但一些观察者认为今年的前六个月相对“缓慢和无趣”。然而,这种观点可能忽略了AI在多个领域的持续进步。本文将探讨为什么我们不应该轻易使用“AI寒冬”这样的说法,并展望2025年作为AI代理之年的潜力。 为何不应轻易使用“…

Linux No space left on device分析和解决

报错解释&#xff1a; "No space left on device" 错误表示你的Linux设备&#xff08;通常是磁盘分区&#xff09;上没有剩余空间了。这可能是因为磁盘已满&#xff0c;或者inode已满。磁盘空间是指磁盘上的实际空间&#xff0c;而inode是用来存储文件元数据的数据结…

嘉立创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作为世…

守护网络安全:从日常生活做起的防护策略

引言 在信息化时代&#xff0c;网络已成为我们生活中不可或缺的一部分。它为我们提供了快速沟通和便捷服务的渠道&#xff0c;使我们能够高效地办理业务、完成工作和享受娱乐。然而&#xff0c;随着网络的普及和信息化程度的加深&#xff0c;我们在享受便利的同时&#xff0c;…

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

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

JavaScript 与 HTML 的结合

在 HTML 页面中嵌入 JavaScript 代码是实现动态效果和交互功能的关键一步。下面是一些常用的方法来实现 JavaScript 与 HTML 的结合。 内联方式&#xff1a;可以直接在 HTML 元素的事件属性中嵌入 JavaScript 代码。例如&#xff0c;可以在按钮的 onclick 属性中添加 JavaScri…

【黑马点评】使用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 批量获取用户…

Command | Ubuntu 个别实用命令记录(新建用户、查看网速等)

1. 实用命令 1.1 系统相关 1.1.1 查看系统、用户信息等 查看当前系统硬件架构 uname -m注&#xff1a;mac 上也能用 查看当前系统的操作系统及版本 cat /etc/os-release | grep "PRETTY_NAME"查看当前系统单个cpu的可用核心数 cat /proc/cpuinfo | grep "…

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

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

不动产证ocr识别场景解析、房产证识别API

不动产证OCR识别、房产证识别接口是通过光学字符识别技术&#xff08;OCR&#xff09;从不动产证书的图像或扫描件中自动提取关键信息的技术应用。该场景的主要目标是提高信息录入的效率&#xff0c;减少人工输入的错误&#xff0c;并能自动化处理大量不动产证书、房产证的数据…

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

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

37 | 实战二(下):重构ID生成器项目中各函数的异常处理代码

平时进行软件设计开发的时候&#xff0c;我们除了要保证正常情况下的逻辑运行正确之外&#xff0c;还需要编写大量额外的代码&#xff0c;来处理有可能出现的异常情况&#xff0c;以保证代码在任何情况下&#xff0c;都在我们的掌控之内&#xff0c;不会出现非预期的运行结果。…

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.外…

Python知识点:如何使用Airflow进行ETL任务调度

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; 要使用Apache Airflow进行ETL任务调度&#xff0c;你可以遵循以下步骤&#xff1…

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;在里面获取文件的所有权之后就可以删除了。 具体…