std::unique_ptr适用于单所有权场景,如函数内临时资源、类成员封装、工厂返回;传参应避免值传递导致所有权转移,优先用make_unique构造;shared_ptr需防循环引用,用weak_ptr打破;C API需自定义删除器;性能上unique_ptr零开销,shared_ptr有原子操作成本。

std::unique_ptr 该用在哪些地方
只允许一个所有者、不需要共享生命周期的场景,比如函数内部临时资源管理、类成员封装原始指针、工厂函数返回新对象——这时候 std::unique_ptr 是最轻量且零开销的选择。
常见错误是把它当成“更安全的 raw pointer”到处传参:一旦你把 std::unique_ptr 通过值传递进函数,所有权就转移了,原变量变空;如果只是想观察或临时使用,应该传 const std::unique_ptr<t>&</t> 或直接传 T* / T&。
- 构造时优先用
std::make_unique<t>(...)</t>,避免裸new和异常安全问题 - 不要对同一块内存重复构造多个
std::unique_ptr,否则析构时 double free - 类中持有资源时,
std::unique_ptr能自动禁用拷贝,强制你思考移动语义是否合理
std::shared_ptr 循环引用怎么破
两个 std::shared_ptr 相互持有对方所管理的对象(比如父子节点、观察者-被观察者),引用计数永远不为 0,对象永远不会析构——这是最典型的泄漏源头。
解决方法不是少用 std::shared_ptr,而是明确谁该“强引用”,谁该“弱引用”。只要把其中一端换成 std::weak_ptr,就能打破循环。
立即学习“C++免费学习笔记(深入)”;
-
std::weak_ptr不增加引用计数,访问前必须调用lock()得到临时std::shared_ptr,失败说明对象已销毁 - 不要用
std::shared_ptr管理数组(除非自定义删除器),C++17 前std::shared_ptr<int>(new int[10])</int>会调用delete而非delete[] - 避免从裸指针隐式构造
std::shared_ptr,比如std::shared_ptr<t>(raw_ptr)</t>,容易和已有std::shared_ptr指向同一地址但各自计数
智能指针和 C 风格 API 怎么共存
调用 fopen、malloc、pthread_create 这类需要手动释放的 C 接口时,不能直接塞给 std::unique_ptr 或 std::shared_ptr,否则默认用 delete 释放,导致未定义行为。
必须显式提供删除器(deleter):对 fopen 用 fclose,对 malloc 用 free,对 POSIX 线程句柄用 pthread_join 或 pthread_detach。
std::unique_ptr<file decltype> fp(fopen("x.txt", "r"), &fclose)</file>- 删除器类型必须匹配,函数指针要带
decltype,lambda 需用std::function或模板推导(可能影响 size) - 跨 DLL 边界传递智能指针要小心:不同模块可能用不同 CRT,
new/delete不匹配会崩溃
性能敏感代码里智能指针还安全吗
std::unique_ptr 几乎没运行时开销,和裸指针一样快;std::shared_ptr 的原子引用计数、控制块分配、虚表跳转(自定义 deleter)确实有成本,在 tight loop 或高频分配路径上得掂量。
别为了“统一风格”强行套用:高频小对象(如 vector 元素)不该用 std::shared_ptr 包一层;而网络连接、大缓冲区、长生命周期服务对象,用 std::shared_ptr 换取清晰的所有权边界,收益远大于那点原子操作。
- 用
std::make_shared<t>()</t>一次分配控制块 + 对象,比先new T再构造std::shared_ptr少一次 malloc - 频繁拷贝
std::shared_ptr时,考虑是否真需要共享所有权,还是该用std::shared_ptr+std::weak_ptr分离观察与持有 - 调试时注意:ASan/UBSan 可能无法捕获智能指针误用(比如
weak_ptr::lock()后解引用空指针),得靠静态分析或单元测试覆盖
真正难的不是语法,是每次 new 之前问一句:这个资源的生命周期边界在哪?谁创建,谁销毁,谁可能还在用?答案清楚了,选哪个智能指针,其实没太多犹豫空间。









