C++智能指针make_shared比直接new+shared_ptr好在哪
C++11 引入了智能指针来管理动态内存,std::shared_ptr 是最常用的一种。但在创建 std::shared_ptr 时,直接使用 new 和使用 std::make_shared 存在显著差异。以下是详细的对比分析与实操指南。
1. 分析内存分配次数
直接使用 new 配合 shared_ptr 构造函数,会导致内存分配两次。而使用 make_shared 仅分配一次。
理解 new + shared_ptr 的行为:
当执行 std::shared_ptr<T> p(new T) 时:
- 执行
new T:在堆上分配一块内存用于存放对象T。 - 执行
shared_ptr构造函数:在堆上分配第二块内存(控制块),用于存放引用计数、删除器等管理信息。
理解 make_shared 的行为:
当执行 auto p = std::make_shared<T>() 时:
- 执行
make_shared:编译器申请一块连续的内存,同时容纳对象T和控制块。
使用 Mermaid 流程图对比两种方式的内存布局差异:
结论:减少内存分配次数能降低 CPU 开销,并减少内存碎片,提高缓存命中率。
2. 检查异常安全性
在函数参数传递时,使用 new 可能会导致内存泄漏。
分析 潜在的泄漏场景:
假设有一个函数接收两个参数,一个是 shared_ptr,另一个是复杂的对象。
void process(std::shared_ptr<Resource> res, AnotherObject obj);
如果这样调用:
// 危险写法
process(std::shared_ptr<Resource>(new Resource()), createAnotherObject());
C++ 标准不限制参数的求值顺序。编译器可能按照以下步骤执行:
- 执行
new Resource()(对象创建成功)。 - 调用
createAnotherObject()(假设该函数抛出异常)。 - 异常抛出,程序跳转到异常处理,
shared_ptr构造函数尚未执行,导致第一步创建的Resource内存泄漏。
使用 make_shared 解决问题:
// 安全写法
process(std::make_shared<Resource>(), createAnotherObject());
由于 make_shared 是一个函数调用,资源创建和控制块构造在函数内部完成,要么全成,要么全不成。即使 createAnotherObject() 抛出异常,make_shared 内部已创建的智能指针会自动负责销毁资源。
3. 对比代码性能与可读性
通过表格直接查看两种方式在关键维度上的差异。
| 特性 | new + shared_ptr |
make_shared |
优势方 |
|---|---|---|---|
| 内存分配次数 | 2 次 | 1 次 | make_shared |
| 代码简洁度 | 需重复写类型名 | 使用 auto 自动推导 |
make_shared |
| 异常安全 | 不安全(特定场景) | 安全 | make_shared |
| 对象销毁时机 | 引用归零即销毁 | 引用归零且无 weak_ptr 时才释放 |
new + shared_ptr |
优化 代码书写:
直接写 new 必须重复类型名,容易笔误且冗余:
std::shared_ptr<MyComplexClass> ptr(new MyComplexClass(arg1, arg2));
使用 make_shared 配合 auto:
auto ptr = std::make_shared<MyComplexClass>(arg1, arg2);
4. 注意使用限制与特殊情况
尽管 make_shared 通常是首选,但在一种特殊情况下需要使用 new:当对象非常大,且使用了 std::weak_ptr 时。
理解 内存释放机制:
new方式:当shared_ptr引用计数归零,对象内存立即释放。控制块内存需等到所有weak_ptr引用归零才释放。make_shared方式:对象和控制块在同一块内存。只有当shared_ptr和weak_ptr引用都归零时,这块内存才会被释放。
场景:如果有一个占用 1GB 内存的对象,且有一个 weak_ptr 长期存活(例如用于缓存检查),即使用户不再使用该对象,这 1GB 内存也会一直占用,直到 weak_ptr 到期。
操作 解决步骤:
- 判断 对象内存占用是否极大。
- 检查 是否存在生命周期可能很长的
weak_ptr。 - 如果满足上述两点,使用
new+shared_ptr来确保大对象内存能及时释放。

暂无评论,快来抢沙发吧!