循环引用发生在两个对象互相持有对方的shared_ptr时,导致引用计数无法归零;将其中一个改为weak_ptr可打破循环,因其不增加引用计数,仅观察对象是否存在,从而避免内存泄漏。

在C++中,weak_ptr 主要用来解决 shared_ptr 可能引发的循环引用问题。当两个或多个对象通过 shared_ptr 相互持有对方时,引用计数永远无法归零,导致内存泄漏。weak_ptr 提供了一种“观察”资源的方式,而不增加引用计数,从而打破这种循环。
循环引用是如何发生的?
考虑两个类 A 和 B,它们各自持有一个指向对方的 shared_ptr:
class B; // 前向声明class A {
public:
std::shared_ptr ptr;
~A() { std::cout };
class B {
public:
std::shared_ptr ptr;
~B() { std::cout };
如果这样使用:
auto a = std::make_shared();auto b = std::make_shared();
a->ptr = b;
b->ptr = a;
此时,a 和 b 的引用计数都是2。当作用域结束时,a 和 b 的局部引用被释放,引用计数减为1,但由于彼此仍互相引用,析构函数不会被调用,造成内存泄漏。
立即学习“C++免费学习笔记(深入)”;
weak_ptr 如何打破循环?
将其中一个 shared_ptr 改为 weak_ptr,即可打破循环引用。weak_ptr 不增加引用计数,只是“弱引用”或“观察”目标对象是否存在。
酷纬企业网站管理系统Kuwebs是酷纬信息开发的为企业网站提供解决方案而开发的营销型网站系统。在线留言模块、常见问题模块、友情链接模块。前台采用DIV+CSS,遵循SEO标准。 1.支持中文、英文两种版本,后台可以在不同的环境下编辑中英文。 3.程序和界面分离,提供通用的PHP标准语法字段供前台调用,可以为不同的页面设置不同的风格。 5.支持google地图生成、自定义标题、自定义关键词、自定义描
修改上面的例子:
class B;class A {
public:
std::shared_ptr ptr;
~A() { std::cout };
class B {
public:
std::weak_ptr ptr; // 改为 weak_ptr
~B() { std::cout };
现在,只有 A 持有 B 的强引用,而 B 持有 A 的弱引用。当外部引用 a 和 b 离开作用域时:
- a 的引用计数从1降到0,A 被销毁
- A 销毁后,其持有的 b 引用减少,B 的引用计数也归零,B 被销毁
- 整个资源被正确释放
weak_ptr 的使用方式
由于 weak_ptr 不保证所指对象仍然存在,访问前必须先检查:
std::shared_ptr lock_ptr = b.ptr.lock();if (lock_ptr) {
// 对象还活着,可以安全使用
std::cout } else {
// 对象已被销毁
std::cout }
lock() 方法尝试获取一个 shared_ptr,如果原对象已释放,返回空 shared_ptr。
典型应用场景
- 父-子结构:父节点用 shared_ptr 持有子节点,子节点用 weak_ptr 指向父节点,避免循环
- 缓存系统:缓存表用 weak_ptr 观察对象,不阻止其销毁
- 观察者模式:观察者用 weak_ptr 弱引用目标,防止因循环引用导致内存泄漏
基本上就这些。weak_ptr 不复杂但容易忽略,合理使用能有效避免 shared_ptr 的循环引用陷阱。关键是理解它“只观察、不拥有”的特性。










