在C++中,std::shared_ptr是一种智能指针,能够通过引用计数机制实现多个指针安全地共享同一个动态对象。它的设计目标是让内存释放不再依赖手动delete,而是由所有使用者的生命周期共同决定。

引用计数的基本工作方式
std::shared_ptr在内部维护两块信息:一个是指向实际对象的原始指针,另一个是指向控制块(control block)的指针。控制块里保存了当前的引用计数、弱引用计数以及删除器等相关数据。
当我们用同一个对象去构造或者拷贝一个shared_ptr时,控制块中的引用计数会原子地加一;当一个shared_ptr被销毁或重新指向别处时,引用计数会原子地减一。一旦计数降为0,shared_ptr就会调用删除器来释放被管理的对象。
常见操作对计数的影响
- 拷贝构造或拷贝赋值:引用计数加一
- 析构或重置(reset):引用计数减一
- 使用std::move转移:原指针置空,计数不变
简单代码示例
下面这段代码展示了shared_ptr拷贝时引用计数的变化过程:
#include <iostream>
#include <memory>
int main() {
// 创建一个shared_ptr,此时引用计数为1
std::shared_ptr<int> p1 = std::make_shared<int>(42);
std::cout << "p1 use_count: " << p1.use_count() << std::endl;
// 拷贝p1,引用计数变为2
std::shared_ptr<int> p2 = p1;
std::cout << "after copy p2, use_count: " << p1.use_count() << std::endl;
// p2重置,引用计数变回1
p2.reset();
std::cout << "after reset p2, use_count: " << p1.use_count() << std::endl;
// p1离开作用域,计数变为0,对象被释放
return 0;
}
为什么需要注意循环引用
如果两个对象各自通过std::shared_ptr互相指向对方,那么它们的引用计数都不会降到零,从而造成内存泄漏。此时应该使用std::weak_ptr来打破这种强引用循环。
weak_ptr不会增加引用计数,它只是对对象的弱观察,需要通过lock方法尝试提升为shared_ptr才能安全访问。
引用计数的线程安全性
标准规定,引用计数的修改是原子操作,因此多个线程同时拷贝或销毁指向同一对象的shared_ptr是安全的。但要注意,被管理对象本身的读写并不因此自动线程安全,仍需额外同步。
| 操作 | 是否影响引用计数 | 线程安全 |
|---|---|---|
| 拷贝shared_ptr | 是,加一 | 是 |
| reset shared_ptr | 是,减一 | 是 |
| 访问被管理对象 | 否 | 不保证 |
小结
std::shared_ptr通过分离对象与控制块,用原子引用的方式追踪使用者数量,从而实现了灵活且相对安全的内存共享管理。掌握它的计数规则,能帮助我们写出更稳健的C++程序。
std::shared_ptr引用计数内存管理修改时间:2026-07-29 07:18:19