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

用C++11 make_shared替代shared_ptr

我们先看一下shared_ptr的成员结构

shared_ptr 由继承_Ptr_base而来

class shared_ptr : public _Ptr_base<_Ty>

_Ptr_base有两个成员,_Ptr用于指向管理的资源,_Rep用于指向引用计数对象

template <class _Ty>
class _Ptr_base {

private:
    element_type* _Ptr{nullptr};
    _Ref_count_base* _Rep{nullptr};
}

_Ref_count_base对象有两个成员,_Uses 表示有多少个shared_ptr指向资源,_Weaks表示有多少个weak_ptr指向资源

// CLASS _Ref_count_base
class __declspec(novtable) _Ref_count_base {
private:
    _Atomic_counter_t _Uses  = 1;   // 多少个shared_ptr指向资源
    _Atomic_counter_t _Weaks = 1;   // 多少个weak_ptr观察资源
}
shared_ptr<int> sp1(new int(10));

在这里插入图片描述

shared_ptr<int> sp2(sp1);  // 调用shared_ptr的拷贝构造,引用计数_Uses++,只存在一个引用计数对象
weak_ptr<int> wp2(sp1);    // 调用weak_ptr的拷贝构造,引用计数_Weaks++,只存在一个引用计数对象

调用智能指针的拷贝构造,会修改相应的引用计数,如果调用智能指针的构造函数,就会产生新的引用计数对象

  • int(10)这块资源释放:只要_Uses为0,立马释放
  • 引用计数对象空间释放:_Uses和_Weaks全都为0

即这两块内存分两次new出来的,可以分开释放,weak_ptr的lock方法会返回shared_ptr,会使得_Uses++而_Weaks不变

手动调用new缺陷: 如果 shared_ptr sp1(new int(10)) 这行代码中的new int(10) 执行成功了,而shared_ptr的构造函数执行失败了,就不会有引用计数的_Ref_count_base对象,就意味着不存在shared_ptr对象,就不会调用shared_ptr的析构函数,那我们new出来的堆区资源也就不会释放了

shared_ptr<int> sp3 = make_shared<int>(10);

在这里插入图片描述
用make_shared的原理如图,代码上不会再看见显式的new运算符,我们如果调用shared_ptr构造函数时,会手动new一次资源,shared_ptr的构造函数又会new一个引用计数的对象,如果两次new不能都成功,就会有资源泄露

而make_shared把资源和引用计数的对象放在连续的空间中,就只需要new一次,解决了上面的问题。new失败没有资源泄露,new成功析构函数会释放资源

make_shared优点: 申请空间效率高,防止了资源泄露

make_shared缺点:

  1. 无法自定义删除器,默认析构函数是delete,无法管理打开的文件。如果想自定义删除器,还得使用第一个版本
  2. 分配的资源空间和引用计数对象的空间是连续的,是一次性申请的,也需要一次性释放,导致托管的资源延迟释放

由于使用make_shared分配的资源空间和引用计数对象的空间是连续的,是一次性申请的,也需要一次性释放。所以对于make_shared new出来的内存,就算引用计数_Uses为0,而_Weaks不为0,无论是int(10)的空间还是引用计数对象空间都不能释放,因为_Weaks不为0,引用计数对象空间不能释放,整块资源都不能释放

同样的,也需要用make_unique代替unique_ptr

相关文章:

  • 数据结构之——栈的操作讲解与功能实现
  • 剑指 Offer II 079+080+081+082
  • 前端小tips(持续更新)
  • matlab读取文件
  • php __destruct反序列化原理
  • 通俗易懂,一文学会前端缓存
  • python常用基础笔记
  • centos设置root免密自动登陆
  • JuiceFS 在多云存储架构中的应用 | 深势科技分享
  • 【LeetCode】思维向题笔记总结(持续更新)
  • springboot+vue农产品销售配送网站
  • ISE的FPGA程序加载与固化——Omapl138/TMS320C6748+FPGA核心板
  • SAP ABAP 定义事件以及处理事件
  • 西瓜书-2习题
  • 中国LED封装行业发展前景预测与投资战略规划分析报告
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • 2017-08-04 前端日报
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • ESLint简单操作
  • golang中接口赋值与方法集
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • nfs客户端进程变D,延伸linux的lock
  • PermissionScope Swift4 兼容问题
  • Python3爬取英雄联盟英雄皮肤大图
  • vuex 笔记整理
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 人脸识别最新开发经验demo
  • 深入浅出webpack学习(1)--核心概念
  • 十年未变!安全,谁之责?(下)
  • 我与Jetbrains的这些年
  • 移动端 h5开发相关内容总结(三)
  • 用jquery写贪吃蛇
  • 最近的计划
  • 【干货分享】dos命令大全
  • #define
  • (4.10~4.16)
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (办公)springboot配置aop处理请求.
  • (二)斐波那契Fabonacci函数
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (四)Android布局类型(线性布局LinearLayout)
  • (一)RocketMQ初步认识
  • (原)记一次CentOS7 磁盘空间大小异常的解决过程
  • .net core Swagger 过滤部分Api
  • .net core webapi Startup 注入ConfigurePrimaryHttpMessageHandler
  • .NET Core 实现 Redis 批量查询指定格式的Key
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • .net中调用windows performance记录性能信息
  • ::before和::after 常见的用法
  • @AliasFor注解
  • [ 云计算 | AWS 实践 ] Java 如何重命名 Amazon S3 中的文件和文件夹
  • [CF703D]Mishka and Interesting sum/[BZOJ5476]位运算