以下是C++中std::make_shared
的用法详解及核心要点,结合实践场景和代码示例说明:
📌 一、基本用法与语法
std::make_shared
是C++11引入的模板函数,用于创建并管理std::shared_ptr
智能指针,语法如下:
#include <memory>
std::shared_ptr<T> ptr = std::make_shared<T>(构造参数...);
示例:
class MyClass {
public:
MyClass(int v) : data(v) {}
private:
int data;
};
int main() {
auto obj = std::make_shared<MyClass>(42); // 创建对象并初始化
return 0;
}
- 作用:替代
new T(...)
,自动管理内存生命周期,避免手动delete
。
⚡ 二、核心优势
1. 性能优化(一次内存分配)
- 传统方式(
std::shared_ptr<T>(new T)
):
先分配对象内存,再分配控制块(引用计数等),共 2次内存分配。 - **
make_shared
:
将对象和控制块合并为单次内存分配**,减少内存碎片,提升性能(约30%速度提升)std::shared_ptr<int> p1(new int(10)); // 2次分配(低效) auto p2 = std::make_shared<int>(10); // 1次分配(高效)
2. 异常安全
- 若构造函数抛出异常,
make_shared
能保证已分配的内存被自动释放,而传统方式可能泄漏:
由于// 传统方式:若computePriority()抛出异常,new int的内存泄漏 process(std::shared_ptr<int>(new int), computePriority()); // make_shared:异常安全 process(std::make_shared<int>(), computePriority());
make_shared
是原子操作,避免了中间状态导致的内存泄漏。
3. 代码简洁性
- 避免显式
new
,减少代码冗余。
🧩 三、实际应用场景
1. 共享对象所有权
多个shared_ptr
共享同一对象,引用计数归零时自动释放:
auto obj = std::make_shared<MyClass>();
auto obj2 = obj; // 引用计数+1
std::cout << obj.use_count(); // 输出2
对象在obj
和obj2
均析构后释放。
2. 解决循环引用
使用weak_ptr
打破循环依赖:
class B;
class A {
public:
std::weak_ptr<B> b_ptr; // 弱引用
};
class B {
public:
std::shared_ptr<A> a_ptr;
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b; // 弱引用,不增加计数
b->a_ptr = a; // 强引用
return 0; // 正确释放资源
}
若使用shared_ptr
互相持有会导致内存泄漏。
3. 高效创建数组(C++20+)
// C++20支持make_shared创建数组
auto arr = std::make_shared<int[]>(5);
arr[0] = 42;
C++11/14需手动构造:std::shared_ptr<int[]>(new int[5])
。
⚠️ 四、使用限制与注意事项
不支持自定义删除器
make_shared
无法指定删除器,需直接使用shared_ptr
构造函数auto ptr = std::shared_ptr<FILE>(fopen("file.txt", "r"), [](FILE* f){ fclose(f); });
延迟内存释放问题
适用场景:对内存敏感的系统需谨慎使用。
对象内存和控制块合并分配后,若存在weak_ptr
,则对象内存需等到所有weak_ptr
析构才释放(强引用计数为0时仅析构对象,内存块可能未释放)。私有构造函数限制
若类构造函数为private
或protected
,需通过友元或静态工厂函数间接调用make_shared
。
🛠️ 五、最佳实践建议
- **优先使用
make_shared
**:除非需要自定义删除器或处理私有构造,否则默认选用。 - 避免循环引用:成员指针优先用
weak_ptr
,尤其父子对象互相引用时。 - 性能敏感场景:高频创建对象时(如实时系统),
make_shared
的性能优势更显著。
💎 总结
std::make_shared
是现代C++内存管理的核心工具:
- 高效:单次内存分配提升性能;
- 安全:异常安全避免泄漏;
- 简洁:代码更清晰易维护。
在共享所有权、资源自动释放及高性能场景中不可或缺,但需注意其内存释放机制和构造限制。