智能指针是C++11后管理资源的首选:unique_ptr用于独占所有权,零开销且防拷贝;shared_ptr仅在真需共享时使用,须防循环引用;禁用get()构造新智能指针或跨作用域传递;自定义删除器适配非内存资源。

别用 new 和 delete 手动配对管理资源——这是 C++11 之后智能指针存在的根本理由。用错 std::unique_ptr 或 std::shared_ptr,轻则性能下降、循环引用,重则内存泄漏或双重释放。
什么时候必须用 unique_ptr?
当你需要「独占所有权」且不打算共享时,unique_ptr 是唯一合理选择。它零开销、不可拷贝、可移动,天然适配容器和工厂函数。
- 函数返回动态对象:用
std::make_unique构造,避免裸指针泄露(...) - 作为类成员管理私有资源(如文件句柄、自定义 buffer):析构自动释放,无需手写
~Class() - 放进
std::vector等容器:只有unique_ptr能高效移动,shared_ptr会多一次原子计数开销 - 不能赋值或拷贝:若误写
auto p2 = p1;,编译器直接报错,这是保护而非限制
std::unique_ptrcreate_int() { return std::make_unique (42); // OK:移动语义隐式触发 } // auto p2 = p1; // 编译错误:copy constructor is deleted
shared\_ptr 的引用计数不是万能的
shared_ptr 的核心代价是原子引用计数——每次拷贝、赋值、析构都涉及原子操作。更危险的是,它无法自动解决循环引用。
- 仅在「真正需要共享所有权」时使用:比如多个对象需同时持有同一缓存对象
- 永远优先用
std::make_shared:比(...) shared_ptr少一次内存分配(new T(...)) - 警惕
this捕获:在 lambda 中捕获shared_ptr很容易导致对象无法释放 - 循环引用必须用
std::weak_ptr打断:父-子、观察者-被观察者等双向关联场景下,一方必须用weak_ptr
struct Node {
std::shared_ptr parent;
std::shared_ptr child; // ❌ 若 parent 和 child 互指,引用计数永不归零
};
// ✅ 正确做法:child 改为 std::weak_ptr 不要混用裸指针、智能指针和 get()
get() 返回的是原始指针,它不延长生命周期,也不参与所有权管理——这是最常踩的坑。
立即学习“C++免费学习笔记(深入)”;
- 禁止用
get()结果去构造另一个智能指针:std::shared_ptr会导致双重释放(p.get()) - 禁止把
get()存入容器或跨作用域传递:一旦原智能指针析构,裸指针立刻悬空 - 只在调用 C 风格 API(如
fread(buf, 1, n, fp))时临时使用get(),且确保智能指针生命周期严格长于调用 - 避免
reset(new T):绕过make_unique/make_shared会丢失异常安全保证
自定义删除器不是炫技,而是刚需
默认删除器只调用 delete,但资源不止是堆内存:文件描述符、OpenGL 对象、C 库分配的内存都需要特定清理逻辑。
- 用 lambda 或函数对象传入删除器,类型成为
unique_ptr的一部分 -
shared_ptr的删除器在构造时捕获,之后不可变;unique_ptr删除器通常为类型模板参数,影响 sizeof - 注意:C 风格数组要用
default_delete,否则delete p而非delete[] p
auto file_deleter = [](FILE* f) { if (f) fclose(f); };
std::unique_ptr fp(fopen("log.txt", "w"), file_deleter);
// 数组场景
std::unique_ptr> arr(new int[100]);
智能指针不是银弹。unique_ptr 用错成 shared_ptr 会拖慢性能;shared_ptr 忘记打断循环引用,程序会在某个深夜悄悄吃光内存;而任何对 get() 的滥用,都在把 RAII 变回手动内存管理。










