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

make_shared的使用

目录

1. make_shared 的基本概念

基本用法

2. 引入 make_shared 的主要原因

2.1 解决传统构造方式的问题

2.2 标准委员会的动机

3. make_shared 的核心优势

3.1 性能优势(最重要优点)

内存分配优化:

性能提升表现:

3.2 异常安全(关键优势)

3.3 代码简洁性(显著优势)

配合 auto 使用更清晰:

4. make_shared 的实现原理

4.1 典型实现伪代码


1. make_shared 的基本概念

make_shared 是 C++11 引入的模板函数,用于创建并返回一个指向动态分配对象的 shared_ptr。它是创建共享所有权对象的标准推荐方式。

基本用法
auto ptr = std::make_shared<MyClass>(arg1, arg2...);

2. 引入 make_shared 的主要原因

2.1 解决传统构造方式的问题

传统 shared_ptr 构造方式:

std::shared_ptr<MyClass> ptr(new MyClass(arg1, arg2...));

这种方式存在三个潜在问题:

  • 内存分配分离:需要两次内存分配(对象+控制块)
  • 异常不安全:可能在构造过程中发生内存泄漏
  • 代码冗余:需要重复类型名称

异常导致泄漏的场景

当执行 std::shared_ptr<MyClass> ptr(new MyClass(arg1, arg2...)) 时,实际分为两个关键内存操作:

  • 执行 new MyClass(arg1, arg2...)分配 “对象本身” 的内存,并调用构造函数初始化 MyClass 对象。
  • 构造 shared_ptr分配 “控制块” 的内存(控制块用于记录引用计数、弱引用计数等元信息),然后让 shared_ptr 接管第一步创建的对象。

如果在 ** 步骤 2(分配控制块)** 时发生异常(比如内存不足,抛出 std::bad_alloc),问题就会出现:

  • 步骤 1 已经成功创建了 MyClass 对象(内存已分配,构造函数已执行)。
  • 但步骤 2 失败,shared_ptr 没有被成功构造,也就没有指针能管理第一步创建的对象
  • 最终,这个 new 出来的 MyClass 对象既没有被智能指针接管,也没有被手动 delete,导致内存泄漏(对象的内存永远无法被释放)。
2.2 标准委员会的动机

C++标准委员会引入 make_shared 主要基于:

  • 性能优化:减少内存分配次数
  • 异常安全:保证原子性操作
  • 代码简洁:改善编码体验

3. make_shared 的核心优势

3. make_shared 的核心优势

3.1 性能优势(最重要优点)
内存分配优化:

典型实现的内存布局

make_shared 分配的内存块:
+-------------------+-------------------+
| 控制块 (refcount) | 对象数据          |
+-------------------+-------------------+
性能提升表现:
  • 缓存友好:控制块和对象在同一缓存行
  • 减少碎片:单次分配减少内存碎片
  • 分配更快:内存分配是昂贵操作

基准测试通常显示 make_shared 比传统方式快 10-30%

3.2 异常安全(关键优势)

考虑以下可能抛出异常的代码:

void process(std::shared_ptr<X> x, std::shared_ptr<Y> y);process(std::shared_ptr<X>(new X), std::shared_ptr<Y>(new Y));

问题在于:

  • new X 成功
  • new Y 抛出异常
  • 已分配的 X 内存泄漏

解释

  • 先执行 new X,成功分配了 X 类型的内存,并得到裸指针 X*
  • 接着执行 new Y,但此时内存不足(或其他原因),new Y 抛出异常(比如 std::bad_alloc)。

异常导致 “裸指针未被智能指针接管”

当 new Y 抛出异常时,整个 process 函数的调用会被中断。此时:

  • 第一个参数 std::shared_ptr<X>(new X) 还没完成 “shared_ptr 封装裸指针” 的过程(因为参数计算被异常打断了);
  • 也就是说,new X 分配的内存,只有裸指针,没有被 shared_ptr 接管(智能指针的 “自动释放” 能力没生效)。

使用 make_shared 的解决方案:

process(std::make_shared<X>(), std::make_shared<Y>());

这样要么全部成功,要么全部回滚,不会泄漏资源。

3.3 代码简洁性(显著优势)
// 传统方式(重复类型名)
std::shared_ptr<VeryLongTypeName> p(new VeryLongTypeName(args...));// make_shared 方式(简洁)
auto p = std::make_shared<VeryLongTypeName>(args...);
配合 auto 使用更清晰:
auto widget = std::make_shared<Widget>(color, size);

4. make_shared 的实现原理

4.1 典型实现伪代码
//make_shared的实现
//伪代码
template<typename T, typename... Args>
shared_ptr<T> my_make_shared(Args&& ...args)
{//先开辟控制块和对象大小的空间void* p = ::operator new(sizeof(ContorlBlock) + sizeof(T));//构造控制块ContorlBlock* cb = new(p) ControlBlock();//获取到对象的地址T* obj = reinterpret_cast<T*>(static_cast<char*>(p) + sizeof(ContorlBlock));//给对象进行构造 使用定位new,使用完美转发保持右值属性new(obj) T(std::forward(Args)(args)...);return shared_ptr<T>(cb, obj);
}	

文章转载自:

http://cdLKv2gS.zyndj.cn
http://bk4YkIsw.zyndj.cn
http://8Q9DAvW6.zyndj.cn
http://65JwM7MU.zyndj.cn
http://tbxfPWeq.zyndj.cn
http://F1Vh2zGA.zyndj.cn
http://HNr4Funj.zyndj.cn
http://8sVQ4Sr4.zyndj.cn
http://KPfGigLV.zyndj.cn
http://pxlClhhy.zyndj.cn
http://iRDBD36c.zyndj.cn
http://D64QS2pn.zyndj.cn
http://Qj19zsbv.zyndj.cn
http://JGQWIONp.zyndj.cn
http://711naomU.zyndj.cn
http://FXl0mqCC.zyndj.cn
http://o2nnh8wf.zyndj.cn
http://RAQ4jnBR.zyndj.cn
http://qseeaewH.zyndj.cn
http://3zIYxiGB.zyndj.cn
http://8aSHkyHw.zyndj.cn
http://mBVbEhnH.zyndj.cn
http://1GsYuFqE.zyndj.cn
http://3DFoNxLa.zyndj.cn
http://rQmKkEAg.zyndj.cn
http://rEKm8xzE.zyndj.cn
http://PA68Ak7y.zyndj.cn
http://SfZH1dL4.zyndj.cn
http://ZBdXC39G.zyndj.cn
http://OvQFIuyv.zyndj.cn
http://www.dtcms.com/a/372205.html

相关文章:

  • 《九江棒球》未来十年棒垒球发展规划·棒球1号位
  • agentscope1.0安装与测试
  • Shell 脚本自动安装 Nginx
  • 《探索C++11:现代语法的内存管理优化“性能指针”(下篇)》
  • Basic Pentesting: 1靶场渗透
  • NAS自建笔记服务leanote2
  • 对比Java学习Go——程序结构与变量
  • 【JavaWeb】一个简单的Web浏览服务程序
  • [C/C++学习] 7.“旋转蛇“视觉图形生成
  • webhook(Web 钩子)是什么?
  • 《2025年AI产业发展十大趋势报告》四十三
  • java面试小册(1)
  • NW506NW507美光固态闪存NW525NW539
  • [Maven 基础课程]再看下第一个 Maven 项目
  • Keil快捷键代码补全
  • 2024理想算法岗笔试笔记
  • Java面试-线程安全篇
  • 线程池深度解析:ThreadPoolExecutor底层实现与CompletableFuture异步编程实战
  • 计算机网络学习(七、网络安全)
  • 蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
  • build.gradle里面dependencies compile和api的区别
  • C++20格式化字符串:std::format的使用与实践
  • UART 使用教程
  • cuda中线程id的计算方式(简单)
  • Archon02-代码解析
  • # 图片格式转换工具:重新定义您的图片处理体验
  • 【Python】S1 基础篇 P2 列表详解:基础操作
  • 液压伺服千斤顶系统设计cad+设计说明书
  • MySQL 锁机制解析
  • directive-plugin指令插件相关参数文档