1. 共享式智能指针的前世今生
第一次接触shared_ptr是在2013年接手一个遗留C++项目时。当时项目里到处都是new和delete的裸指针操作,内存泄漏问题频发。在重构过程中,shared_ptr就像救命稻草般出现,但随之而来的却是循环引用导致的内存泄漏新问题。这种"刚解决老问题又冒出新问题"的经历,让我深刻意识到:理解shared_ptr不能停留在表面API调用,必须吃透其底层机制。
shared_ptr作为C++11引入的智能指针三剑客之一(另外两个是unique_ptr和weak_ptr),本质上是通过引用计数实现的自动内存管理工具。与unique_ptr的独占所有权不同,shared_ptr允许多个指针共享同一对象的所有权,当最后一个持有对象的shared_ptr销毁时,才会自动释放内存。这种特性使其成为多线程环境下共享对象的理想选择。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解剖shared_ptr的内部结构
2.1 控制块:引用计数的神经中枢
每个被shared_ptr管理的对象都附带一个控制块(control block),这是实现引用计数的核心数据结构。控制块通常包含:
- 强引用计数(use_count):记录有多少个shared_ptr共享该对象
- 弱引用计数(weak_count):记录weak_ptr的引用情况
- 删除器(deleter):定制化销毁逻辑
- 分配器(allocator):内存分配策略
cpp复制// 简化版控制块结构示意
struct ControlBlock {
std::atomic<long> use_count;
std::atomic<long> weak_count;
void(*deleter)(void*);
void* managed_object;
};
关键细节:控制块的内存位置决定了shared_ptr的构造成本。当通过make_shared创建时,对象和控制块会分配在连续内存中,这比分别分配效率更高。
2.2 引用计数操作的多线程安全
shared_ptr的线程安全性常被误解。实际上:
- 引用计数本身是原子操作,保证增减计数的线程安全
- 被管理对象本身的访问仍需额外同步机制
- 同一个shared_ptr实例的多线程写操作
