在C++程序里,使用new分配的对象如果忘记delete就会产生内存泄漏,而多次delete又会导致未定义行为。shared_ptr通过引用计数方式,在最后一个持有对象的指针销毁时自动释放内存,让开发者不必手动调用delete。

shared_ptr的基本用法
使用make_shared是创建shared_ptr的推荐方式,它比直接用new更安全且效率更高。下面演示如何定义和使用:
#include <iostream>
#include <memory>
int main() {
// 使用make_shared创建智能指针
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = p1; // 引用计数变为2
std::cout << "值: " << *p1 << std::endl;
std::cout << "引用计数: " << p1.use_count() << std::endl;
p2.reset(); // p2释放,计数减为1
std::cout << "重置后计数: " << p1.use_count() << std::endl;
return 0;
}
引用计数是如何工作的
每个shared_ptr内部都维护一个指向控制块的指针,控制块中记录着引用计数。当发生拷贝时计数加一,当指针析构或调用reset时计数减一。计数为零时,托管对象和控制块都被释放。
| 操作 | 引用计数变化 |
|---|---|
| 拷贝构造或赋值 | 加1 |
| 析构或reset | 减1 |
| 计数为0 | 释放对象 |
避免循环引用
如果两个类互相持有对方的shared_ptr,就会形成循环引用,导致计数永远不为0。此时应使用weak_ptr打破循环。weak_ptr不增加引用计数,只观察对象是否还存活。
#include <memory>
struct B; // 前向声明
struct A {
std::shared_ptr<B> b_ptr;
};
struct B {
std::weak_ptr<A> a_ptr; // 使用weak_ptr避免循环
};
使用时的注意事项
- 不要用同一个原始指针构造多个shared_ptr,否则会重复释放。
- 优先使用make_shared而非shared_ptr<T>(new T)。
- 不要将this直接交给shared_ptr,应使用enable_shared_from_this。
- 在多线程中传递shared_ptr是安全的,但对象本身的访问仍需加锁。
小结
shared_ptr通过RAII和引用计数极大简化了C++内存管理。理解其计数规则和循环引用问题,能帮助我们写出更健壮的程序。在需要共享所有权的场景下,它是最实用的智能指针工具。
shared_ptrRAII引用计数修改时间:2026-07-26 20:18:18