C++——shared_ptr:make_shared的用处,与shared_ptr直接构造的区别

shared_ptr

shared_ptr继承自__shared_ptr,其中有两个对象,一个是指向资源的指针,一个是控制块,指向一个引用计数对象。控制块中存储了强引用和弱引用的计数,强引用Uses代表shared_ptr对象的引用计数,弱引用Weaks代表weak_ptr对象的引用计数。
在这里插入图片描述
大概结构如上图所示,控制块其中也存储了指向资源的指针。
因此在构造一个shared_ptr对象的时候,会有两次堆分配,一次是为资源分配,一次是为控制块分配。因为每一个指向这份资源的指针对象都需要看到同一份引用计数,因此跟资源一样也是堆分配的。多次的堆分配和释放也就代表效率上的损失,而且极易产生内存碎片。

make_shared

C++11同时提供了make_shared函数,这是通过构造一个shared_ptr对象,而这个对象会事先申请一块足够大的内存空间,用于存放管理的资源以及控制块。即分配的堆空间是连续的,因此只有一次堆内存分配。

在这里插入图片描述
内存的结构就从左边的构造shared_ptr对象到右边的重构对象资源指针和引用计数。
相比shared_ptr构造,减少一次内存分配,提高效率,并且内存空间连续,减少内存碎片产生。但是,make_shared也存在缺点。

make_shared的缺点

自定义deleter

make_shared在构造智能指针对象的时候不能自定义deleter。在创建对象时同时创建控制块,这个控制块内部包含了引用计数、deleter等与管理资源相关的信息。因为资源和控制块是属于同一块申请的内存,所以使用自定义deleter可能会导致控制块内存被不正确地释放。因此,如果要使用deleter,应该使用shared_ptr直接构造。

构造函数

因为make_shared需要用到类的拷贝构造,因此需要被管理的类的构造函数是public的。

内存延迟归还

因为分配的空间是连续的,在资源指针的Uses变为0之后,控制块伴随资源的资源不会被立即释放,要等Weak也变为0,整块内存才被释放。资源只是被clear,但是但是没有归还操作系统。而如果是默认的控制块,在资源指针的Uses变为0之后,资源会被立即释放,内存立即归还。

通过调试看直接构造和make_shared的区别

void test2()
{std::shared_ptr<string> p1 = std::make_shared<std::string>(10, '9');{std::weak_ptr<std::string> wptr1;wptr1 = p1;std::shared_ptr<string> p2 = std::make_shared<std::string>("Hello");wptr1 = p2;p2 = p1;}std::cout << "end";
}void test1()
{std::shared_ptr<string> p1 = std::shared_ptr<std::string>(new std::string(10, '9'));{std::weak_ptr<std::string> wptr1;wptr1 = p1;std::shared_ptr<string> p2 = std::shared_ptr<std::string>(new std::string("Hello"));wptr1 = p2;p2 = p1;}std::cout << "end";
}int main()
{test1();test2();return 0;
}

直接构造在这里插入图片描述

当wptr指向p1的时候,可以看到p1的Weaks变为了2,weak_ptr观察到的内容与p1一致。并且注意此时control block的value显示为default,表示默认的控制块。
在这里插入图片描述
当weak_ptr指向p2,并且将p2指向p1,意思就是p2原来管理的Hello资源要释放掉,然后用p1拷贝构造一个对象,赋值给p2,让p1和p2同时管理10个9。
此时可以看到weak_ptr的资源指针已经显示Error reading,说明资源已经释放,内存已经归还了。

make_shared构造

在这里插入图片描述
此时可以看到原来为default的control block已经改为了make_shared。
在这里插入图片描述
重复之前的操作,把p2指向p1,再看weak_ptr的成员。可以看到ptr指向的资源并没有被释放,只是内容并清空而已。只有当weak_ptr的生命周期结束,整个内存块才会被释放,归还给操作系统。
这就是make_shared最主要的缺点,在某些内存要求高的场景下可能不太适用。

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

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

相关文章

OLED透明屏显示技术:未来显示科技的领航者

OLED透明屏显示技术是一种创新性的显示技术&#xff0c;它的特殊性质使其成为未来显示科技的领航者。 OLED透明屏具有高对比度、快速响应时间、广视角和低功耗等优势&#xff0c;同时&#xff0c;其透明度、柔性和薄型设计使其成为创新设计的理想选择。 本文将深入探讨OLED透…

Linux——常用命令大汇总(带你快速入门Linux)

纵有疾风起&#xff0c;人生不言弃。本文篇幅较长&#xff0c;如有错误请不吝赐教&#xff0c;感谢支持。 &#x1f4ac;文章目录 一.终端和shell命令解析器终端和shell命令解析器概述终端提示符的格式常用快捷键 二.Linux命令格式帮助文档&#xff1a;man 三.目录基础知识Wind…

基于RabbitMQ的模拟消息队列之二---创建项目及核心类

一、创建项目 创建一个SpringBoot项目&#xff0c;环境&#xff1a;JDK8&#xff0c;添加依赖&#xff1a;Spring Web、MyBatis FrameWork(最主要&#xff09; 二、创建核心类 1.项目分层 2.核心类 在mqserver包中添加一个包&#xff0c;名字为core&#xff0c;表示核心类…

博流RISC-V芯片Eclipse环境搭建

文章目录 1、下载 Eclipse2、导入 bouffalo_sdk3、编译4、烧录5、使用ninja编译 之前编译是通过 VSCode 编译&#xff0c;通过手工输入 make 命令编译&#xff0c;我们也可以通过 Eclipse 可视化 IDE 来编译、烧录。 1、下载 Eclipse 至 Eclipse 官网 https://www.eclipse.org…

软件测试Day5|软件测试理论03

白盒测试方法 针对程序的代码进行测试&#xff0c;代码覆盖率高&#xff1b;缺点&#xff1a;覆盖所有代码路径大、业务功能可能覆盖不全、测试开销大 静态方法&#xff1a;1&#xff09;桌面检查&#xff08;一个人检查&#xff09;&#xff1b;2&#xff09;代码审查&#…

『SpringBoot 源码分析』run() 方法执行流程:(2)刷新应用上下文-准备阶段

『SpringBoot 源码分析』run() 方法执行流程&#xff1a;&#xff08;2&#xff09;刷新应用上下文-准备阶段 基于 2.2.9.RELEASE问题&#xff1a;当方法进行了注释标记之后&#xff0c;springboot 又是怎么注入到容器中并创建类呢&#xff1f; 首先创建测试主程序 package …

Spring——Spring Boot基础

文章目录 第一个helloword项目新建 Spring Boot 项目Spring Boot 项目结构分析SpringBootApplication 注解分析新建一个 Controller大功告成,运行项目 简而言之&#xff0c;从本质上来说&#xff0c;Spring Boot 就是 Spring&#xff0c;它做了那些没有它你自己也会去做的 Spri…

积跬步至千里 || 数学基础、算法与编程

数学基础、算法与编程 1. BAP 技能 BAP 技能是指基础(Basic)、算法(Algorithm)和编程(Programm)三种基本技能的深度融合。理工科以数学、算法与编程为根基&#xff0c;这三个相辅相成又各有区别。 &#xff08;1&#xff09;数学以线性代数为主要研究工具和部分微积分技术为手…

【广州华锐互动】AR远程连接专家进行协同管理,解放双手让协同更便捷

AR远程协同系统是一种基于AR技术&#xff0c;实现远程设备维修和技术支持的系统。该系统通过将虚拟信息叠加在现实世界中&#xff0c;实现对设备的全方位监控和管理&#xff0c;并可以通过AR眼镜等终端设备&#xff0c;实时查看设备的各项数据和信息&#xff0c;为设备维修提供…

我能“C“——指针进阶(上)

目录 指针的概念 1. 字符指针 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 4. 数组参数、指针参数 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 5. 函数指针 阅读两段有趣的代码&…

Message: ‘chromedriver‘ executable may have wrong permissions.

今天运行项目遇到如下代码 driverwebdriver.Chrome(chrome_driver, chrome_optionsoptions)上述代码运行报错如下&#xff1a; Message: chromedriver executable may have wrong permissions. Please see https://sites.google.com/a/chromium.org/chromedriver/home出错的原…

输出图元(四)8-2 OpenGL画点函数、OpenGL画线函数

4.3 OpenGL画点函数 要描述一个点的几何要素&#xff0c;我们只需在世界坐标系中指定一个位置。然后该坐标位置和场景中已有的其他几何描述一起被传递给观察子程序。除非指定其他属性值&#xff0c;OpenGL 图元按默认的大小和颜色来显示。默认的图元颜色是白色&#x…