make_shared和new有什么区别 性能优势与内存分配分析

std::make_shared比直接使用new配合std::shared_ptr更高效,因为它通过一次内存分配同时创建对象和控制块,减少开销、提升缓存局部性并增强异常安全;而new方式需两次分配,性能较低且存在异常安全隐患;但当需要自定义删除器、构造函数非公开或存在weak_ptr长期持有场景时,只能或应慎用std::make_shared,此时可选择new方式以获得更大灵活性,总结:常规场景优先使用std::make_shared,特殊需求下退回到new并注意资源管理问题。

make_shared和new有什么区别 性能优势与内存分配分析

std::make_shared

和直接使用

new

配合

std::shared_ptr

构造在功能上都能实现共享所有权的智能指针,但它们在性能、异常安全和内存管理方面存在显著差异。下面从内存分配、性能优势和实际使用角度详细分析两者的区别

1. 内存分配方式不同

当你使用

new

创建对象并传递给

std::shared_ptr

时:

std::shared_ptr ptr(new Foo());

这会执行 两次独立的内存分配

一次是

new Foo()

为对象本身分配内存;一次是

std::shared_ptr

内部为了管理引用计数(control block),需要额外分配一块内存来存储引用计数、弱引用计数等元信息。

而使用

std::make_shared

auto ptr = std::make_shared();

它会 一次性分配一块连续内存,同时包含:

对象实例的数据;控制块(引用计数等管理信息)。

这种优化称为 内存共置(allocation elision)合并分配(combined allocation)

2. 性能优势对比

std::make_shared

的优势:

减少内存分配次数:从两次变为一次,显著降低动态内存分配的开销(

malloc

/

free

是昂贵操作)。

提高缓存局部性:对象和控制块在内存中相邻,访问时更可能命中同一缓存行,提升性能。

更快的构造速度:由于只做一次分配,且内部使用完美转发构造对象,效率更高。

异常安全更好:考虑如下代码:

// 潜在问题:如果 make_shared 之前抛异常,可能造成资源泄漏functionThatTakesSharedPtr(std::shared_ptr(new Foo), expensiveCall());

参数求值顺序未定义,

new Foo

expensiveCall()

哪个先执行不确定。如果

expensiveCall()

抛异常,而

new Foo

已执行但尚未交给

shared_ptr

管理,则会发生内存泄漏。

而使用

make_shared

是原子操作,避免此类问题。

new + shared_ptr

的劣势:

多一次内存分配 → 更慢、更多碎片。更差的缓存表现。异常安全性差(如上所述)。

3. 什么时候不能用

make_shared

尽管

make_shared

有很多优点,但在某些场景下无法使用:

(1)自定义删除器(custom deleter)

std::shared_ptr ptr(new Foo, [](Foo* p){ /* custom cleanup */ });
std::make_shared

不支持传入删除器。此时只能用

new

(2)私有/受保护构造函数

如果类的构造函数不是公开的,

make_shared

无法访问(因为它需要在内部构造对象),除非你提供友元或工厂方法。

(3)启用

weak_ptr

长期持有时的内存问题

make_shared

将对象和控制块一起分配,这意味着:

即使对象早已析构(引用计数为0),但如果还有

weak_ptr

指向它,那么那块合并的内存 无法释放,直到最后一个

weak_ptr

也被销毁。

这是因为控制块和对象共用一块内存。而

new + shared_ptr

方式中,对象和控制块分开分配,对象可以在引用归零时立即释放,仅保留控制块供

weak_ptr

使用。

所以,如果你预期对象很快析构但

weak_ptr

会长时间存在,

make_shared

可能导致内存延迟释放。

4. 实际建议

场景 推荐方式

普通对象创建,无特殊需求✅ 优先使用 @@######@@需要自定义删除器❌ 必须用 @@######@@ + @@######@@构造函数非 public❌ 通常不能用 @@######@@对象生命周期短但 @@######@@ 长期存在⚠️ 谨慎使用 @@######@@,考虑内存延迟释放问题高性能关键路径✅ 优先 @@######@@,减少分配和提升缓存效率

总结

std::make_shared

new

更高效:一次分配、更好的缓存、异常安全

shared_ptr

方式更灵活:支持自定义删除器、特殊构造控制。在绝大多数常规场景下,应优先使用

make_shared

。特殊需求下才退回到

weak_ptr

,并注意异常安全问题。

基本上就这些,不复杂但容易忽略细节。

make_shared
make_shared
make_shared
new + shared_ptr
new
std::make_shared
new

以上就是make_shared和new有什么区别 性能优势与内存分配分析的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1471887.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月18日 19:10:55
下一篇 2025年12月18日 19:11:13

相关推荐

发表回复

登录后才能评论
关注微信