

新闻资讯
技术学院该用 std::unique_ptr 而不是 std::shared_ptr 的核心判断标准是所有权是否需要共享:unique_ptr 表示独占所有权,转移后原指针自动置空;shared_ptr 通过引用计数允许多方共享同一对象。
std::unique_ptr 而不是 std::shared_ptr
核心判断标准是所有权是否需要共享:std::unique_ptr 表示独占所有权,转移后原指针自动置空;std::shared_ptr 通过引用计数允许多方共享同一对象。如果只是临时封装堆内存、函数返回资源、或作为容器元素管理单个对象,优先选 unique_ptr —— 它零开销、无原子操作、不引入循环引用风险。
常见误用场景:
shared_ptr 当作“更安全的 unique_ptr”随意传参,结果拖慢性能且掩盖设计问题shared_ptr 管理本该由类自身生命周期决定的对象(比如内部缓存),导致对象存活时间超出预期shared_ptr 但没意识到控制块(control block)的引用计数是原子操作,有轻微开销unique_ptr 的正确构造与移动语义unique_ptr 不支持拷贝,只支持移动。直接赋值或传参时若忘记 std::move(),编译器会报错:use of deleted function 'std::unique_ptr。
推荐写法:
std::make_unique(...) 构造,避免裸 new 和异常安全问题unique_ptr 时,直接 return std::make_unique(x); ,调用方自动接收右值void f(std::unique_ptr p) ),表示函数要接管所有权;如只需观察,改用 T* 或 T&
std::unique_ptrp1 = std::make_unique (42); std::unique_ptr p2 = std::move(p1); // ✅ 正确:显式移动 // std::unique_ptr p3 = p1; // ❌ 编译失败
shared_ptr 的循环引用与 weak_ptr 解法两个 shared_ptr 相互持有对方管理的对象(例如双向链表节点、父子对象关系),会导致引用计数永远不为 0,内存泄漏。这是 shared_ptr 最典型的陷阱。
解决方式不是少用 shared_ptr,而是识别“观测性引用”并替换为 std::weak_ptr:
weak_ptr 不增加引用计数,调用 lock() 可尝试升级为 shared_ptr,失败说明对象已销毁shared_ptr,子持父用 weak_ptr
weak_ptr 本身不保证线程安全,但 lock() 是原子的struct Node {
std::shared_ptr next;
std::weak_ptr prev; // 避免循环引用
};
auto a = std::make_shared();
auto b = std::make_shared();
a->next = b;
b->prev = a; // ✅ 不增加 a 的引用计数
unique_ptr 和 shared_ptr 都支持自定义删除器,但语法和默认行为不同:
unique_ptr 是合法类型,析构时自动调用 delete[];而 shared_ptr 在 C++17 前不被标准支持,C++17 起才允许,但仍需显式传入 default_delete
unique_ptr 模板参数的一部分(影响类型),所以 unique_ptr != unique_ptr ;而 shared_ptr 的删除器是运行期绑定的,类型不变make_shared 无法指定自定义删除器,必须用裸 new + 构造函数方式// unique_ptr 数组(推荐) std::unique_ptr真正难的不是记住语法,是每次写arr = std::make_unique (10); // shared_ptr 数组(C++17+) std::shared_ptr arr2(new int[10], std::default_delete ());
shared_ptr 时多问一句:“这个对象,到底有没有别的地方也该负责它的生死?”——没想清楚就先用 unique_ptr。