该用 unique_ptr 时:所有权必须唯一、零开销、需移动语义转移;该用 shared_ptr 时:多对象共享、需引用计数,但须防循环引用,可用 weak_ptr 破解。

什么时候该用 unique_ptr,而不是 shared_ptr
所有权必须唯一时,选 unique_ptr;多个对象需要共享同一块内存时,才考虑 shared_ptr。前者零开销、无引用计数,后者有原子操作和内存分配成本。
常见错误现象:shared_ptr 被无意复制(比如传值进函数、存入容器),导致生命周期延长难以调试;unique_ptr 被拷贝编译直接报错:use of deleted function。
- 网络请求回调里持有资源?用
unique_ptr+std::move交给回调对象 - 缓存池里多个模块读同一份配置?用
shared_ptr,但注意别在循环引用场景下用 - 构造
unique_ptr优先用std::make_unique,避免裸new后异常导致泄漏 -
shared_ptr构造务必用std::make_shared,它把控制块和对象内存合并分配,比分开 new 更快
shared_ptr 循环引用怎么破
两个 shared_ptr 相互持有对方管理的对象,引用计数永远不归零,内存永远不释放——典型表现是程序运行越久越卡,Valgrind 报 “still reachable” 内存。
根本原因:引用计数只看“谁持有”,不分析“谁真正需要”。解决不是靠手动 reset(),而是从设计上切断强引用链。
立即学习“C++免费学习笔记(深入)”;
- 一方改用
weak_ptr:比如父节点用shared_ptr指向子节点,子节点用weak_ptr回指父节点 -
weak_ptr访问前必须调lock(),返回shared_ptr或空指针,不能直接解引用 - 别在 lambda 捕获列表里直接写
[ptr = shared_from_this()],容易隐式延长生命周期;改用[weak_this = weak_from_this()]+lock()
unique_ptr 怎么安全地交出所有权
unique_ptr 的核心机制就是“移动语义”,不能拷贝,只能转移。想让它离开当前作用域,必须显式移动。
常见错误现象:函数返回 unique_ptr 却试图用拷贝方式接收;或在容器中存储后,用 at(i) 取出来直接赋值给另一个 unique_ptr,编译失败。
- 返回时直接
return std::make_unique<t>(...)</t>,编译器会自动应用移动语义 - 存入
std::vector<:unique_ptr>></:unique_ptr>后,取出来要转移:用std::move(vec[i]),不是vec[i] - 函数参数想接收所有权?声明为
void f(std::unique_ptr<t> ptr)</t>,调用时传std::move(ptr) - 万不得已需临时观察内容(不交出所有权),用
ptr.get()获取裸指针,但别存、别 delete、别用于构造新智能指针
自定义删除器为什么常被忽略
默认删除器只对 new 出来的对象调 delete,但 C++ 里大量资源不是 new 来的:C 风格 API 返回的 FILE*、OpenGL 的 GLuint、Windows 的 HANDLE……不用自定义删除器,unique_ptr 析构时就会调错函数,轻则资源泄漏,重则崩溃。
性能影响不大,但逻辑正确性全靠它。而且删除器类型是 unique_ptr 模板的一部分,unique_ptr<int decltype></int> 和 unique_ptr<int></int> 是完全不同的类型。
- 封装 FILE*:
std::unique_ptr<file decltype> fp(fopen("x.txt", "r"), &fclose)</file> - 避免用 lambda 做删除器(除非加
noexcept且捕获为空),否则可能增加 sizeof,也影响模板推导 - 用
std::default_delete显式写出,比裸写delete更清晰,尤其配合数组:unique_ptr<int std::default_delete>></int>
最麻烦的从来不是语法怎么写,而是搞清“谁该负责释放”以及“释放时该调哪个函数”。智能指针只是工具,所有权契约得人来定。










