在 C++ 中,shared_ptr 的实现原理是怎样的?同时,shared_ptr 是否具备线程安全性?请结合使用场景说明。
考察说明
考查对 shared_ptr 底层原理及其线程安全语义的理解。
回答思路
- 【回答框架 1】shared_ptr 的核心原理是引用计数:每个 shared_ptr 实例共享同一份控制块,控制块中保存引用计数和弱计数。构造、拷贝、赋值、析构时通过原子操作增减计数,当强引用计数降为 0 时释放管理的对象,弱计数用于支持 weak_ptr。
- 【回答框架 2】shared_ptr 的线程安全分为两层:同一 shared_ptr 对象被多个线程同时读取其拷贝是安全的,因为拷贝构造和析构对控制块引用计数的增减是原子操作;但多个线程同时修改同一个 shared_ptr 对象(如同时进行赋值或 reset)是不安全的,需要外部加锁。
- 【回答框架 3】指向同一对象的多个不同 shared_ptr 实例之间的拷贝和析构是线程安全的,但对象本身的读写并发安全由程序员负责,shared_ptr 不保证管理对象的线程安全。
- 【回答框架 4】常见误区是认为 shared_ptr 完全线程安全,实际上它仅保证引用计数的原子性,不保证指向对象的并发访问安全,也不保证同一实例的并发写操作安全。
- 【回答框架 5】在实现中,引用计数通常使用原子变量(如 atomic<long>),而无锁或无等待操作可能因平台而异,标准只要求线程安全级别的保证。
- 【关键点 1】shared_ptr 的核心原理是引用计数:每个 shared_ptr 实例共享同一份控制块,控制块中保存引用计数和弱计数。构造、拷贝、赋值、析构时通过原子操作增减计数,当强引用计数降为 0 时释放管理的对象,弱计数用于支持 weak_ptr。
- 【关键点 2】shared_ptr 的线程安全分为两层:同一 shared_ptr 对象被多个线程同时读取其拷贝是安全的,因为拷贝构造和析构对控制块引用计数的增减是原子操作;但多个线程同时修改同一个 shared_ptr 对象(如同时进行赋值或 reset)是不安全的,需要外部加锁。
- 【关键点 3】指向同一对象的多个不同 shared_ptr 实例之间的拷贝和析构是线程安全的,但对象本身的读写并发安全由程序员负责,shared_ptr 不保证管理对象的线程安全。