std::make_shared比直接使用new配合std::shared_ptr更高效,因为它通过一次内存分配同时创建对象和控制块,减少开销、提升缓存局部性并增强异常安全;而new方式需两次分配,性能较低且存在异常安全隐患;但当需要自定义删除器、构造函数非公开或存在weak_ptr长期持有场景时,只能或应慎用std::make_shared,此时可选择new方式以获得更大灵活性,总结:常规场景优先使用std::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
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
new + shared_ptr
的劣势:
多一次内存分配 → 更慢、更多碎片。更差的缓存表现。异常安全性差(如上所述)。
3. 什么时候不能用
make_shared
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
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
微信扫一扫
支付宝扫一扫