1. 为什么需要智能指针管理多线程资源?
在C++多线程编程中,资源管理一直是个令人头疼的问题。我曾在项目中遇到过这样的场景:主线程创建了一个对象,多个工作线程需要访问这个对象,当主线程认为对象不再需要时直接销毁,而此时可能还有工作线程正在访问该对象——结果就是经典的"悬垂指针"问题,程序随机崩溃且难以复现。
智能指针通过引用计数机制完美解决了这个问题。以shared_ptr为例,当最后一个持有对象的shared_ptr被销毁时,对象才会被自动删除。在多线程环境下,引用计数的增减是原子操作,保证了线程安全。但要注意,这仅保证指针本身的线程安全,并不保证所指对象的线程安全。
重要提示:智能指针的线程安全分为两个层面:
- 控制块(引用计数)的线程安全 - 所有智能指针都保证
- 所指对象的线程安全 - 需要开发者自己保证
2. 三种智能指针的线程安全特性
2.1 shared_ptr:共享所有权模型
shared_ptr的引用计数是原子操作,多个线程可以同时拷贝/析构同一个shared_ptr而不会导致计数错误。但要注意:
cpp复制// 线程不安全的典型场景
if(!sharedPtr.expired()) {
// 这里其他线程可能已经reset了指针
sharedPtr->doSomething();
}
// 正确做法:先转为强引用
auto localPtr = sharedPtr.lock();
if(localPtr) {
localPtr->doSomething();
}
实测发现,在4核CPU上频繁创建/销毁shared_ptr时,原子操作带来的性能损耗约比普通指针高15-20%。对于性能敏感场景,可以考虑以下优化:
- 尽量减少shared_ptr的拷贝传递,使用const引用
- 对于只读对象,使用shared_ptr
- 使用make_shared避免额外内存分配
2.2 unique_ptr:独占所有权模型
unique_ptr不可拷贝,但可以通过move转移所有权。在多线程中使用时:
cpp复制// 主线程
auto uniqueData = std::make_unique<Data>();
std::
