Appearance
智能指针(Smart Pointers)专题
一句话总览
智能指针是 RAII(资源获取即初始化)思想的产物:把「裸指针 + 手动 delete」封装进对象,让内存(或任意资源)随对象生命周期自动释放。C++11 起标准库提供 unique_ptr、shared_ptr、weak_ptr。
三类智能指针速览
| 智能指针 | 所有权 | 特点 | 代价 / 限制 |
|---|---|---|---|
unique_ptr | 独占 | 轻量、无额外内存开销、可自定义删除器 | 不可拷贝,只可 move |
shared_ptr | 共享 | 引用计数,最后一个释放时销毁对象 | 控制块开销 + 原子计数,有循环引用风险 |
weak_ptr | 观察 | 不增加引用计数,可升级为 shared(lock) | 专破循环引用 / 缓存观测 |
高频问题清单(含答案)
1. 为什么需要智能指针?RAII 是什么?
答案
RAII(资源获取即初始化)把资源生命周期绑定到对象生命周期,析构自动释放;智能指针借此避免忘 delete、异常路径泄漏、重复释放。
2. unique_ptr 能否拷贝?如何转移所有权?
答案
不可拷贝(拷贝构造/赋值被 =delete),只能移动。用 std::move(up) 把所有权转移到另一个 unique_ptr,源变空。
3. shared_ptr 引用计数存在哪、是否线程安全?
答案
存在堆上的控制块(control block)里,多个 shared_ptr 共享。计数增减是原子操作、线程安全;但被指对象本身的访问不因 shared_ptr 而自动线程安全。
4. weak_ptr 的作用?如何打破循环引用?
答案
weak_ptr 不增加引用计数、是观察者;lock() 成功则临时提升为 shared_ptr 安全访问。A、B 互相持有 shared_ptr 会循环引用(计数永不归零泄漏),把其中一方换成 weak_ptr 即可打破。
5. 手写 shared_ptr / unique_ptr(高频压轴题)
答案
unique_ptr 存裸指针 + 删除器,禁拷贝、实现移动;shared_ptr 用指针 + 控制块(强/弱计数),拷贝增计数、析构减到零则 delete。完整实现见 手写实现专题 · 手写智能指针。
6. shared_ptr 的 control block 布局?make_shared 优点?
答案
控制块含强计数、弱计数、删除器、分配器。make_shared 把对象和控制块一次分配(省一次 malloc、缓存更友好),缺点是 weak_ptr 会拖住整块内存直到弱计数也归零。
7. 智能指针 + 裸指针混用有什么坑?
答案
用同一裸指针建多个 shared_ptr 会各自计数、导致 double free;shared_ptr 释放后裸指针悬垂。应尽量用 make_shared/make_unique,避免裸指针与智能指针混用。
8. enable_shared_from_this 为什么存在?
答案
让对象能从自己的 this 安全地得到 shared_ptr(内部持有 weak_ptr),避免从裸 this 再建一个 shared_ptr 造成 double free。
9. 自定义删除器怎么传?
答案
unique_ptr 删除器是模板参数(类型的一部分、无额外开销、每个对象可不同);shared_ptr 删除器存在控制块(同类型 shared_ptr 可各自带不同删除器)。
10. 智能指针会不会导致内存泄漏?
答案
会。shared_ptr 循环引用(A↔B 互相持有)使计数永不归零 → 泄漏。用 weak_ptr 打破循环。详见 weak_ptr.md。
子文档
| 文件 | 内容 |
|---|---|
unique_ptr.md | 独占所有权、move、删除器、手写 |
shared_ptr.md | 引用计数、控制块、make_shared、线程安全、手写 |
weak_ptr.md | 循环引用、lock、expired |
../handwrite/smart-pointer.md | 手写实现已迁到 手写实现专题:shared_ptr 控制块 + weak_ptr::lock + make_shared,另有容器 / optional / flat hashmap / 并发件 |