0

0

C++中std::make_shared为什么比直接new一个shared_ptr效率更高? (内存分配优化)

穿越時空

穿越時空

发布时间:2026-02-16 11:55:38

|

184人浏览过

|

来源于php中文网

原创

std::make_shared只分配一次内存,因为它将控制块和对象置于同一块连续内存中;而手动构造shared_ptr需分别分配对象和控制块,至少两次堆分配。

c++中std::make_shared为什么比直接new一个shared_ptr效率更高? (内存分配优化)

std::make_shared 为什么只分配一次内存

因为 std::make_shared 把控制块(control block)和对象本身放在同一块连续内存里,而手动用 new 构造 std::shared_ptr 时,控制块和对象是分开分配的——至少两次堆分配。

  • 控制块存引用计数、弱引用计数、删除器等元数据,必须存在,但位置可选
  • std::make_shared<t>(args...)</t> 内部调用 operator new(sizeof(control_block) + sizeof(T)) 一次性申请
  • 手动写 std::shared_ptr<t>(new T(args...))</t>:先一次分配 T,再一次分配控制块,共两次 malloc/堆操作
  • 在频繁创建小对象(如 std::shared_ptr<int></int>)时,这差异会被放大

哪些情况会让 std::make_shared 失效甚至更慢

不是所有构造场景都适合 std::make_shared;它依赖完美转发 + placement new,一旦构造过程绕过它,优势就没了,甚至引发额外开销。

  • 类定义了私有或删除的 operator newstd::make_shared 无法调用自定义分配器,可能编译失败或退回到默认分配
  • 需要自定义删除器(比如用 close 关文件描述符):不能直接用 std::make_shared,得走 std::shared_ptr<t>(new T, deleter)</t>,此时又变回两次分配
  • 类没有 public 构造函数,或构造逻辑依赖外部状态(如需先调用 init()),std::make_shared 无法介入,只能手动 new
  • 某些 STL 实现(如旧版 libstdc++)对数组类型支持不完整:std::make_shared<int>()</int> 可能不工作,而 new int[10] 是合法的

性能差异实际有多大?看典型场景

差异主要体现在分配频次高、对象小、无锁竞争低的场景;真实服务中是否可观测,取决于你的热点路径。

今天学点啥
今天学点啥

秘塔AI推出的AI学习助手

下载
  • 在空循环里创建 100 万个 std::shared_ptr<int></int>:用 std::make_shared 比手动 new 快约 15%–25%,主要是减少 malloc 调用次数和缓存局部性更好
  • 对象较大(如 std::shared_ptr<:vector>></:vector> 占几百字节):分配次数仍是两次 vs 一次,但相对占比下降,性能差通常缩到 5% 以内
  • 启用了 jemalloc 或 mimalloc 等优化分配器时,多次小分配的开销被摊薄,std::make_shared 的收益会减弱,但内存布局优势仍在
  • 注意:如果对象构造函数抛异常,std::make_shared 能保证控制块和对象内存一并释放,不会泄漏——这点常被忽略,但它不是“性能”优势,而是安全底线

std::make_shared 不支持的构造方式怎么补救

当必须绕过 std::make_shared 时,别硬套;优先确保语义正确,再考虑是否值得为那点分配开销手写定制分配器。

立即学习C++免费学习笔记(深入)”;

  • 要自定义删除器:老实用 std::shared_ptr<t>(new T(args...), [](T* p) { /* custom cleanup */ })</t>
  • 要使用非默认分配器(如 std::pmr::polymorphic_allocator):C++17 起可用 std::allocate_shared,传入分配器对象,它也能做到单次分配
  • 类不可移动/不可拷贝且构造参数复杂:检查是否真需要 shared_ptr ——有时 std::unique_ptr + std::move 更轻量,也避免控制块开销
  • 跨 DLL 边界传递 shared_ptr(Windows 上常见):控制块分配器必须一致,否则析构崩溃;这时往往要强制用同一 allocator,std::make_shared 反而难控制,不如显式管理

真正容易被忽略的是:控制块和对象共享内存虽省了一次分配,但也意味着只要还有 weak_ptr 活着,对象内存就不能回收——哪怕 shared_ptr 已全销毁。这个生命周期耦合,在调试内存占用时经常让人困惑。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

750

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

568

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

234

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

209

2025.08.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

417

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

589

2023.08.10

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1111

2023.07.26

查看端口占用情况windows
查看端口占用情况windows

端口占用是指与端口关联的软件占用端口而使得其他应用程序无法使用这些端口,端口占用问题是计算机系统编程领域的一个常见问题,端口占用的根本原因可能是操作系统的一些错误,服务器也可能会出现端口占用问题。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1148

2023.07.27

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

145

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 9.6万人学习

C 教程
C 教程

共75课时 | 4.8万人学习

C++教程
C++教程

共115课时 | 18万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号