结论:用 std::unique_ptr 管理独占资源,用 std::shared_ptr 管理共享资源;必须用 make_unique/make_shared 创建,禁止裸 new;unique_ptr 可移转为 shared_ptr,反之不行;注意循环引用、所有权边界和数组删除器。

直接说结论:用 std::unique_ptr 管理独占资源,用 std::shared_ptr 管理共享资源;别混用裸指针和智能指针初始化,也别用 new 直接构造后赋值给 shared_ptr —— 容易 double-delete 或内存泄漏。
什么时候该用 unique_ptr?
当你明确知道某块内存只属于一个所有者,且生命周期由当前作用域或对象严格控制时。典型场景包括:函数返回动态对象、容器里存指针、RAII 封装资源(如文件句柄、socket)。
- 必须用
std::make_unique<t>()</t>创建,避免裸new:auto ptr = std::make_unique<int>(42); // ✅ 推荐<br>auto ptr2 = std::unique_ptr<int>(new int(42)); // ❌ 不安全,异常可能泄漏
- 不能拷贝,只能移动:
auto a = std::make_unique<int>(10);<br>auto b = std::move(a); // ✅ a 变为空<br>// auto c = a; // ❌ 编译失败
- 析构自动调用
delete,不需手动reset()—— 除非你想提前释放
什么时候该用 shared_ptr?
当多个对象/模块需要共同持有同一块内存,并且谁都不想“强制决定”销毁时机时。常见于观察者模式、缓存、异步回调中跨线程传递数据。
- 必须用
std::make_shared<t>()</t>构造:auto sp = std::make_shared<std::string>("hello"); // ✅ 一次分配,高效<br>auto sp2 = std::shared_ptr<std::string>(new std::string("hello")); // ❌ 两次分配,且异常不安全 - 引用计数在拷贝/赋值时 +1,离开作用域或
reset()时 -1;计数归零才真正释放内存 - 注意循环引用:两个
shared_ptr互相持有对方,会导致永远不释放 —— 此时要用std::weak_ptr打断环
unique_ptr 和 shared_ptr 能相互转换吗?
可以,但有严格限制:
立即学习“C++免费学习笔记(深入)”;
-
unique_ptr→shared_ptr:允许(因为所有权可转移),用移动语义auto up = std::make_unique<int>(100);<br>std::shared_ptr<int> sp = std::move(up); // ✅ up 为空,sp 拿到所有权
-
shared_ptr→unique_ptr:不允许(语义冲突)。你不能把“共享所有权”强行变成“独占”,编译器会拒绝 - 都转成裸指针(
.get())再传参?可以,但立刻失去自动管理能力 —— 这是退化行为,仅限对接 C API 或 legacy 代码
最容易被忽略的坑
不是语法写错,而是对“所有权边界”没想清楚:
- 把
shared_ptr存进容器(如std::vector)后,误以为清空容器就释放了内存 —— 实际上只要还有别的shared_ptr持有它,就不会释放 - 在类成员里用
shared_ptr持有自身(比如回调里捕获shared_from_this()),又没检查this是否已失效,导致访问已析构对象 - 用
unique_ptr管理数组?必须显式指定删除器:auto arr = std::unique_ptr<int[]>(new int[10]); // ✅<br>// auto bad = std::unique_ptr<int>(new int[10]); // ❌ 用 delete 而非 delete[]











