智能指针与所有权
智能指针与所有权
时间:2026/04/09
关键词:所有权、观察者、
unique_ptr、shared_ptr、weak_ptr、自定义删除器
核心目标:把“谁负责释放资源”这件事表达清楚,而不是靠约定和记忆。
1. 为什么现代 C++ 强调所有权
裸指针只能表达:
- “这里有个地址”
但它不能天然表达:
- 谁拥有这个对象
- 谁负责释放
- 是否允许共享
现代 C++ 实践里,第一件要说清的就是所有权。
2. 三种常见关系
2.1 拥有(owning)
对象负责管理资源生命周期。
2.2 观察(non-owning)
对象只访问资源,不负责释放。
2.3 共享拥有(shared owning)
多个对象共同延长同一资源生命周期。
3. unique_ptr:默认首选
1 |
|
特点:
- 独占所有权
- 不可拷贝
- 可移动
- 开销低
经验上:
- 只要不是明确需要共享,优先用
unique_ptr
4. shared_ptr:共享拥有
1 | auto p1 = std::make_shared<std::string>("hello"); |
特点:
- 引用计数
- 多个拥有者
- 生命周期更灵活
代价:
- 控制块
- 原子计数开销
- 更复杂的所有权关系
所以不要把它当默认选项。
5. weak_ptr:打破循环
weak_ptr 不拥有对象,只是观察。
1 | std::weak_ptr<Foo> weak = shared; |
它最重要的作用是:
- 避免两个
shared_ptr互相引用导致循环泄漏
6. 原则:拥有和观察要分开
推荐的接口风格通常是:
1 | void take(std::unique_ptr<Foo> p); // 接管所有权 |
这比“什么都传裸指针”更清楚。
7. 自定义删除器
有些资源不是 delete 释放,例如:
FILE*要fclosemalloc对应free
可以这样包装:
1 |
|
8. 常见误区
8.1 裸指针默认表示拥有
不推荐。
裸指针更适合表达观察关系。
8.2 到处用 shared_ptr
这会让生命周期图变得混乱,还会带来额外开销。
8.3 从 unique_ptr 的 get() 拿到裸指针后乱删
get() 只是观察,不转移所有权。
9. 一页总结
最值得记住的顺序是:
- 默认值语义
- 必须动态分配时优先
unique_ptr - 确实共享拥有时才用
shared_ptr - 观察关系用引用、裸指针或
weak_ptr
如果只记一句:
智能指针不是为了“更高级”,而是为了把所有权表达清楚。