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.rhkb.cn/news/122798.html

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

相关文章

每日一题 1921. 消灭怪物的最大数量

难度&#xff1a;中等 思路&#xff1a; 已知速度和距离&#xff0c;可求时间必定先消灭时间最短的怪物求得时间数组排序&#xff0c;只要在第 i 秒时&#xff0c;time[i] > i &#xff0c;那么就可以消灭第 i 个怪物 代码&#xff1a; class Solution:def eliminateMax…

Leetcode刷题笔记--Hot41-50

1--二叉树的层序遍历&#xff08;102&#xff09; 主要思路&#xff1a; 经典广度优先搜索&#xff0c;基于队列&#xff1b; 对于本题需要将同一层的节点放在一个数组中&#xff0c;因此遍历的时候需要用一个变量 nums 来记录当前层的节点数&#xff0c;即 nums 等于队列元素的…

存储过程报Illegal mix of collations错误的解决方法

CREATE PROCEDURE maxAgeStudent(IN _gender CHAR) BEGINDECLARE maxage INT DEFAULT 0;SELECT max(age) INTO maxage FROM student where gender _gender;SELECT * from student WHERE age maxage and gender _gender; END; 在调用的时候 call maxAgeStudent(1) 产生了报…

Linux之DNS域名解析服务

目录 Linux之DNS域名解析服务 概述 产生原因 作用 连接方式 因特网的域名结构 拓扑 分类 域名服务器类型 ​编辑 DNS域名解析过程 分类 解析图 搭建DNS域名解析服务器 概述 安装软件 bind服务中三个关键文件 主配置文件分析 一般需要修改三部分&#xff1a;…

核辐射检测仪电子测量方案

核辐射检测仪又名辐射检测仪&#xff0c;主要是安检、海关、实验室、金属探测公司等行业使用。但由于2023年8月24日排放核废水&#xff0c;导致海洋遭受核辐射污染&#xff0c;由于大海的净化能力有限&#xff0c;则会导致核废水有可能随着洋流的运动&#xff0c;会流至我国海域…

Python列表排序

介绍一个关于列表排序的sort方法&#xff0c;看下面的案例&#xff1a; """ 列表的sort方法来对列表进行自定义排序 """# 准备列表 my_list [["a", 33], ["b", 55], ["c", 11]]# 排序&#xff0c;基于带名函数 …

依赖导入失败场景和解决方案

在使用 Maven 构建项目时&#xff0c;可能会发生依赖项下载错误的情况&#xff0c;主要原因有以下几种&#xff1a; 下载依赖时出现网络故障或仓库服务器宕机等原因&#xff0c;导致无法连接至 Maven 仓库&#xff0c;从而无法下载依赖。 依赖项的版本号或配置文件中的版本号错…

c语言练习41:深入理解字符串函数strlen strcpy strcat

深入理解字符串函数strlen strcpy strcat 模拟实现&#xff1a;”strlen strcpy strcat strlen strcat: #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<assert.h> strlen 1.通过指针移动模拟 //int my_strlen(char* str) { // size_t c…

MySQL 枚举类型如何定义比较好 tinyint?enum?varchar?

enum介绍 先来介绍一下enum类型吧。 ENUM 是一个字符串对象&#xff0c;其值通常选自一个允许值列表中&#xff0c;该列表在表创建时的列规格说明中被明确地列举。&#xff08;建表的时候写到建表语句里&#xff09; 虽然表面是字符串值&#xff0c;但其内部是数字索引&…

Docker私有镜像仓库(Harbor)安装

Docker私有镜像仓库(Harbor)安装 1、什么是Harbor Harbor是类似与DockerHub 一样的镜像仓库。Harbor是由VMware公司开源的企业级的Docker Registry管理项目&#xff0c;它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。Docker容器应用的…

手把手教会如何掌握Swagger

文章目录 前言一、Swagger重要组件及作用二、SpringBoot集成Swagger1.环境准备2.配置Swagger3.配置Swagger扫描接口4.配置API分组5.拓展&#xff1a;其他皮肤 三、常用注解1.接口注解2.方法及参数注解3.实体类注解效果如图&#xff1a; ![在这里插入图片描述](https://img-blog…

一种影像比对快速提取建筑物要素变化的方法

李和军1,2 李 敏3 李楚钰1,2 唐廷元1,2 胡日查4 (1. 北京市测绘设计研究院, 北京, 100038;2. 城市空间信息工程北京市重点实验室, 北京 100038;3. 北京市地质矿产勘查院信息中心, 北京, 100195;4. 内蒙古测绘地理信息中心, 内蒙古 呼和浩特, 010000) 摘 要&#xff1a;本文围绕…

【LeetCode每日一题合集】2023.8.28-2023.9.3(到家的最少跳跃次数)

文章目录 57. 插入区间823. 带因子的二叉树解法——递推 1654. 到家的最少跳跃次数(BFS&#xff0c;&#x1f6b9;最远距离上界的证明)1761. 一个图中连通三元组的最小度数2240. 买钢笔和铅笔的方案数解法1——完全背包解法2——枚举买了几支钢笔&#xff08;推荐解法&#xff…

qt简易网络聊天室 数据库的练习

qt网络聊天室 服务器&#xff1a; 配置文件.pro QT core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exac…

Kafka3.0.0版本——文件清理策略

目录 一、文件清理策略1.1、文件清理策略的概述1.2、文件清理策略的官方文档1.3、日志超过了设置的时间如何处理1.3.1、delete日志删除&#xff08;将过期数据删除&#xff09;1.3.2、compact日志压缩 一、文件清理策略 1.1、文件清理策略的概述 Kafka 中默认的日志保存时间为…

Cento7 Docker-compose安装以及使用InfluxDB

InfluxDB是一个时序数据库&#xff0c;主要用于监控场景的数据支撑&#xff0c;对于那些写少读多按时间序查询数据的场景是非常适用的。接下来我们用docker-compose的形式安装。首先先装好docker,docker-compose命令 yum -y install yum-utils device-mapper-persistent-data…

【买华为云产品,返CSDN余额红包】,快来薅羊毛!

华为云828营销季火热进行中&#xff0c;9月15日前首次购买华为云产品官网任意一款产品&#xff0c;可获得相应比例的CSDN红包。 热门产品云服务器、域名、商标、主机安全等产品都在其中&#xff0c;任君挑选。 活动优惠价购买后还是获得相应比例余额红包&#xff0c;实际付费金…

游戏软件报错d3dx9_43.dll丢失怎么解决?这5个解决方法可以修复

我想和大家分享一个关于电脑问题的话题——d3dx9_43.dll丢失怎么解决。这个话题对于很多使用电脑的朋友来说&#xff0c;可能是一个非常棘手的问题。d3dx9_43.dll是 DirectX中非常重要的一部分&#xff0c;许多游戏和应用程序都需要它来正常运行。如果丢失了这个文件&#xff0…

Simulink建模与仿真(3)-Simulink 简介

分享一个系列&#xff0c;关于Simulink建模与仿真&#xff0c;尽量整理成体系 1、Simulink特点 Simulink是一个用来对动态系统进行建模、仿真和分析的软件包。使用Simulink来建模、分析和仿真各种动态系统(包括连续系统、离散系统和混合系统)&#xff0c;将是一件非常轻松的事…

万物互联:软件与硬件的协同之道

在当今数字化时代&#xff0c;我们身边的一切似乎都与计算机和互联网有关。从智能手机到智能家居设备&#xff0c;从自动驾驶汽车到工业生产线&#xff0c;无论我们走到哪里&#xff0c;都能看到软件和硬件的协同作用。本文将探讨这种协同作用&#xff0c;解释软件和硬件如何相…