# C++智能指针的区别与选型
面试官问"C++ 有哪几种智能指针,区别是什么",大多数人能列出三个名字,但追问"什么时候该用 unique_ptr、什么时候该用 shared_ptr"就答不清楚了。这道题考的不是背定义,而是你对所有权语义的理解深度。
# 简要回答
三种智能指针本质上对应三种所有权模型:unique_ptr 独占(同一时刻只有一个拥有者)、shared_ptr 共享(多个拥有者通过引用计数协调)、weak_ptr 观察(不参与所有权,只是"看一眼还在不在")。选型的核心原则是:能用 unique_ptr 就不用 shared_ptr,需要打破循环引用才用 weak_ptr。
# 详细回答
智能指针的底层思想是 RAII——把资源的生命周期绑定到对象的生命周期上,构造时获取资源,析构时自动释放,彻底消灭手动 delete 带来的泄漏风险。
unique_ptr — 独占所有权
同一时刻只有一个 unique_ptr 拥有资源。禁止拷贝,只能移动(std::move)。析构时直接 delete,零开销,性能和裸指针一样。90% 的场景应该优先用它——函数内部的局部资源、类的成员变量、工厂函数的返回值,都适合 unique_ptr。
shared_ptr — 共享所有权
多个 shared_ptr 可以指向同一个对象,内部通过引用计数管理生命周期。最后一个 shared_ptr 析构时释放资源。代价是每次拷贝/析构都要原子操作引用计数,比 unique_ptr 重。只有在确实需要多个拥有者的场景才用——比如缓存、观察者模式中的共享资源。
weak_ptr — 弱引用/观察者
不增加引用计数,不参与生命周期管理。通过 lock() 尝试提升为 shared_ptr,如果对象已死就返回空。唯一用途:打破 shared_ptr 的循环引用,或者在不确定对象是否还活着时安全地"探测"一下。
选型决策很简单:默认用 unique_ptr;如果资源确实需要被多处共享,用 shared_ptr;如果出现了循环引用或者需要非拥有性观察,用 weak_ptr。

# 知识拓展
Q:为什么说 unique_ptr 是零开销的?
因为它内部就是一个裸指针,没有引用计数、没有控制块、没有原子操作。编译器优化后,unique_ptr 和裸指针生成的机器码完全一样。
Q:shared_ptr 的性能代价具体在哪?
两方面:一是多了一个控制块的堆分配(用 make_shared 可以合并为一次分配);二是每次拷贝和析构都要做原子加减操作,在高并发场景下这个开销不可忽视。
Q:循环引用是怎么发生的?
A 持有 shared_ptr 指向 B,B 也持有 shared_ptr 指向 A。两者的引用计数永远不会归零,内存永远不会释放。解决办法是把其中一方改成 weak_ptr——weak_ptr 不增加引用计数,打破了循环。
Q:能不能用 unique_ptr 代替 shared_ptr?
如果你能把所有权链条理清楚(谁创建、谁拥有、谁负责销毁),绝大多数场景都可以用 unique_ptr。shared_ptr 往往是"懒得想所有权"的妥协方案,用多了反而容易引入循环引用和性能问题。
评论
验证登录状态...