C/C++|我们为什么应该使用 `std::make_shared` 创建 `std::shared_ptr`

std::make_shared 是 C++11 引入的一个工厂函数,用于创建 std::shared_ptr。与直接使用 new 并将其传递给 std::shared_ptr 构造函数相比,std::make_shared 提供了一种更高效、更安全的方法来分配和管理动态内存。

前置知识1:
当我们调用诸如:

auto ptr = std::shared_ptr<MyClass>(new MyClass(args...));
std::shared_ptr<MyClass> classPtr(new MyClass<args...))

这样的代码的时候,一般有两个过程:

  1. 为对象分配内存:
MyClass* rawPtr = new MyClass(args...);
  1. 控制块内存分配:(即为shared_ptr模版类分配内存)
std::shared_ptr<MyClass> classPtr(rawPtr);

这一步创建了一个std::shared_ptr对象,分配了控制块的内存。控制块包含了引用计数等等信息。

前置知识2:
当你使用 std::make_shared 时:

std::shared_ptr<MyClass> classPtr = std::make_shared<MyClass>(args...);

当你使用 std::make_shared 时,这两个步骤被合并为一个原子操作,进行一次内存分配,分配包括对象和控制块的连续内存

好了,从前置知识里我们应该就能大概猜到 make_shared 的诸多好处,包括但不限于:减少内存分配开销、提高缓存局部性、异常安全等等优势,下面我们来进行详细描述。

使用 make_shared 和 不使用 make_shared 对比分析

1. 更高效的内存分配

单次内存分配:

std::make_shared 会一次性分配对象和控制块所需的内存,而不是两次分配。控制块存储引用计数和弱引用计数信息。单次分配意味着减少了内存分配的开销,提高了效率。

auto ptr = std::make_shared<MyClass>(arg...);
//一次分配对象和控制块内存
//等价于
auto ptr = std::shared_ptr<MyClass>(new Class(args...));
// 两次分配内存,一次用于对象,一次用于控制块

2. 异常安全

如果使用new创建对象的过程中抛出了一场,可能会导致内存泄漏,因为内存已经分配但是没有被shared_ptr管理(或者说压根就没有被用户管理)。

std::make_shared 确保对象和控制块的分配是原子操作,避免了这种情况。

auto ptr = std::shared_ptr<MyClass>(new MyClass(args...));
// 如果构造函数抛出异常,new 分配的内存不会被释放

确保使用 std::make_shared ,如果构造函数抛出异常,内存会被自动释放:

auto ptr = std::make_shared<MyClass>(args...);
// 如果在 make_shared 中抛出异常,不会有内存泄漏

3. 提高代码简洁性

使用 std::make_shared 让代码更简洁,减少了显式使用 new 的机会,使代码更符合现代 C++ 的风格。

auto ptr = std::make_shared<MyClass>(args...);
// 等价于
auto ptr = std::shared_ptr<MyClass>(new MyClass(args...));

没别的,就是优雅。

4. 提高缓存局部性和更少的内存碎片

由于 std::make_shared 使用单次分配,因此在内存中只有一个连续的内存块,而不是两个分散的内存块。这不仅提高了缓存局部性而且还减少了内存碎片,提高了内存使用效率。

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

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

相关文章

关于d3js生成节点画布的个人笔记

实现功能 根据鼠标位置生成节点根据节点位置通过鼠标拖拽生成连线实现自定义线段颜色功能删除节点以及连线功能实现单个节点拖动功能实现整条线路的拖动功能 界面如下&#xff1a; 主要模块介绍 绘制连线 const line svg.selectAll(".line").data(links, d >…

【Linux】Git超详细教程:手把手教你(gitee版)--版本管理+远程仓库克隆(初学者必看!!!)

目录 一、前言 二、git 的深度理解 &#x1f95d; 什么是 git ? &#x1f347; git 的历史发展&#xff08;理解 git 的由来&#xff09; &#x1f34b; 感性理解 git 的版本管理 三、git 的安装 ✨Window 终端安装 ✨Linux 安装 四、git 的工作流程 五、如何在 Linux …

音视频开发—视频相关概念:YUV与RGB

文章目录 YUV相关概念组成部分优点常见的 YUV 格式数据量的计算YUV4:2:0 存储格式平面模式&#xff08;planar):打包模式&#xff08;packed&#xff09; RGB 和 YUV 的定义关系与转换RGB 到 YUV 的转换YUV 到 RGB 的转换 使用场景优缺点 YUV相关概念 YUV 是一种颜色编码格式&…

JVM-JAVA-类加载过程

JVM源码 类加载到 JVM 的过程通过 java 命令执行代码的流程 类加载到 JVM 的过程 在运行一个 main 函数启动程序是&#xff0c;首先需要类加载起把主类加载到 JVM 中 通过 java 命令执行代码的流程 loadClass的类加载过程有如下几步&#xff1a; 类被加载到方法区中后主要包…

Maven项目通过maven central 发布到中央仓库 https://repo.maven.apache.org/ 手把手教学 最新教学

一、注册maven central账号 ​ https://central.sonatype.com/publishing/namespaces 我这里直接使用github账号登录 &#xff0c;可以自己注册或者直接使用google账号或者github账号登录 这里github账号登录之后 应该只出现io.github 下面的io.gitee我也验证过 所以这里出…

Java时间类--JDK8

为什么JDK8会又新增时间相关类呢&#xff1f; ① JDK7的时间对象如果需要比较大小的话&#xff0c;必须都先转换成毫秒值&#xff1b;JDK8则不需要&#xff0c;可以直接比较。 ② JDK7的时间对象可以修改&#xff0c;在多线程环境下就会导致数据不安全&#xff1b;JDK8不能修改…

数据库open报ORA-600 kcratr_scan_lastbwr故障处理---惜分飞

由于断电&#xff0c;导致数据库正常open报ORA-600 kcratr_scan_lastbwr错误 Wed Jan 17 18:23:26 2024 ALTER DATABASE MOUNT Successful mount of redo thread 1, with mount id 1028618590 Database mounted in Exclusive Mode Lost write protection disabled Completed:…

【Git】在错误分支上开发了怎么办

情况一&#xff1a;还未提交 git add . 『暂存修改的代码』git stash 『把暂存的文件提交到git的暂存栈』git checkout 『本该提交代码的分支』git stash pop 『取出暂存栈中的代码』 情况二&#xff1a;已提交 git checkout 『不该提交代码提交了代码的分支』git reset HEA…

输入3个字符串,要求将字母按由小到大顺序输出

对于将3个整数按由小到大顺序输出&#xff0c;是很容易处理的。可以按照同样的算法来处理将3个字符串按大小顺序输出。可以直接写出程序。 编写程序&#xff1a; 运行结果&#xff1a; 这个程序是很好理解的。在程序中对字符串变量用关系运算符进行比较&#xff0c;如同对数值…

【Git 版本管理】合并 + 变更,看懂Git

看懂 Git 合并操作分离 HEAD分离 HEAD 测试 相对引用(^ || ~)操作符 ^相对引用 ^ 测试操作符 ~相对引用 ~ 测试 撤销变更Git ResetGit Revert撤销变更 测试 整理提交记录Git Cherry-pick测试 交互式 rebase交互式 rebase 测试 合并操作 关键字&#xff1a;commit、branch、merg…

Minio篇:初识MinIO

1. MinIO快速入门 1.1.MinIO核心概念 下面介绍MinIO中的几个核心概念&#xff0c;这些概念在所有的对象存储服务中也都是通用的。 对象&#xff08;Object&#xff09; 对象是实际的数据单元&#xff0c;例如我们上传的一个图片。 存储桶&#xff08;Bucket&#xff09; 存储…

基于单片机的机械臂的研究

摘要 &#xff1a; 工业机器人是现代科学技术的融合下的产物&#xff0c;属于机电自动化设备的一种。机械臂作为工业机器人的核心&#xff0c;在提高工业生产效率的同时&#xff0c;也保障了工作人员的身心安全。本文以某款基于单片机的机械臂为例&#xff0c;对机械臂的设计方…

【JAVA SE】多态

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;JAVA 个人主页&#xff1a;Celias blog~ 目录 引言 一、多态 1.1 多态的概念 1.2 多态的实现条件 1.3…

AI未来预测

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经成为了当今世界的热门话题。从自动驾驶汽车到智能家居&#xff0c;从虚拟助手到机器人&#xff0c;AI的应用已经渗透到了我们生活的方方面面。在未来&#xff0c;AI将会继续改变我们的生活方式&#xff0…

深入探讨 Android 的 View 显示过程与源码分析

文章目录 1. 探讨 Android 的 View 显示过程1.1. onFinishInflate1.2. onAttachedToWindow1.3. onMeasure1.4. onSizeChanged1.5. onLayout1.6. onDraw 2. 系统代码分析1.1. onFinishInflate1.2. onAttachedToWindow1.3. onMeasure1.4. onSizeChanged1.5. onLayout1.6. onDraw …

【Spring Boot】SpringBoot 下在 yml 中的 logging 日志配置

文章目录 前言输出日志的级别日志输出的位置日志输出的格式日志文件的存储路径日志文件是否输出到控制台配置Logback 配置日志分组配置日志细粒度配置【logger】 前言 logging 配置主要用于控制应用程序的日志输出行为&#xff0c;可以通过配置定制日志的格式、级别、输出位置…

数字化浪潮中的TPM革新:打造高效生产新范式

在数字化浪潮席卷全球的今天&#xff0c;传统生产管理模式正面临前所未有的挑战与机遇。TPM&#xff08;全面生产维护&#xff09;作为一种先进的生产管理理念&#xff0c;如何在数字化驱动下焕发新的活力&#xff0c;成为制造业转型升级的关键一环。 数字化技术为TPM带来了前…

Ubuntu禁止内核自动更新

查看当前内核版本 uname -v #35~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 7 09:00:52 UTC 2 uname -a Linux GKJ 6.5.0-35-generic #35~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Tue May 7 09:00:52 UTC 2 x86_64 x86_64 x86_64 GNU/Linux uname -r 6.5.0-35-generic 方法1&am…

EureKa是什么?

Eureka 是一个源于 Netflix 公司的开源项目&#xff0c;主要用于实现服务注册和服务发现的功能。它是构建分布式系统中的微服务架构的一个关键组件。下面是对 Eureka 的解释&#xff1a; 基本概念 Eureka 是基于 REST 的服务&#xff0c;主要用于管理微服务架构中的服务实例的…

探秘Flask中的表单数据处理

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、Flask中的表单处理机制 三、Flask表单处理实战 四、处理表单数据的注意事项…