循环引用指两个对象的shared_ptr相互持有,导致引用计数无法归零而内存泄漏;weak_ptr不增加引用计数,可打破循环,通过lock()安全访问对象,常用于父子关系或双向链表中避免内存泄漏。

在C++中,shared_ptr通过引用计数管理对象生命周期,但当两个或多个对象互相持有对方的shared_ptr时,会形成循环引用,导致内存无法释放。这时就需要用到weak_ptr来打破循环。
考虑两个类A和B,每个类都持有一个指向对方的shared_ptr:
struct B; // 前向声明
struct A {
std::shared_ptr<B> ptr;
~A() { std::cout << "A destroyed\n"; }
};
struct B {
std::shared_ptr<A> ptr;
~B() { std::cout << "B destroyed\n"; }
};
如果这样使用:
auto a = std::make_shared<A>(); auto b = std::make_shared<B>(); a->ptr = b; b->ptr = a;
此时a和b的引用计数都是2。离开作用域后,shared_ptr会减少引用计数到1,但由于仍大于0,析构函数不会被调用,造成内存泄漏。
立即学习“C++免费学习笔记(深入)”;
weak_ptr是shared_ptr的观察者,它不增加引用计数。它可以指向一个由shared_ptr管理的对象,但不会阻止对象被销毁。
修改上面的例子,把其中一个shared_ptr换成weak_ptr:
struct B;
struct A {
std::shared_ptr<B> ptr;
~A() { std::cout << "A destroyed\n"; }
};
struct B {
std::weak_ptr<A> ptr; // 改为 weak_ptr
~B() { std::cout << "B destroyed\n"; }
};
现在即使相互引用,也不会形成循环。当外部的shared_ptr离开作用域,引用计数正确归零,对象能被正常释放。
由于weak_ptr不保证所指对象一定存在,访问前必须检查:
推荐方式:
std::shared_ptr<A> temp = b.ptr.lock();
if (temp) {
// 安全使用 temp
std::cout << "Object is alive\n";
} else {
std::cout << "Object has been destroyed\n";
}
这样做既打破了循环引用,又能安全地访问目标对象。
基本上就这些。在设计有父子关系、双向链表或观察者模式等结构时,记得让从属方使用weak_ptr,主导方使用shared_ptr,就能有效避免内存泄漏。
以上就是C++weak_ptr解决shared_ptr循环引用问题的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号