shared_ptr循环引用通过weak_ptr打破,将其中一个shared_ptr改为weak_ptr,避免引用计数无法归零,确保对象析构时内存正确释放,如B类用weak_ptr指向A类,解除所有权依赖,解决内存泄漏。

C++中,
shared_ptr
weak_ptr
要解决
shared_ptr
shared_ptr
weak_ptr
weak_ptr
shared_ptr
weak_ptr
假设我们有两个类
A
B
shared_ptr
#include <iostream>
#include <memory>
class B; // 前向声明
class A {
public:
std::shared_ptr<B> ptrB;
A() { std::cout << "A constructor" << std::endl; }
~A() { std::cout << "A destructor" << std::endl; }
void setB(std::shared_ptr<B> b) { ptrB = b; }
};
class B {
public:
std::shared_ptr<A> ptrA; // 这里是问题所在
B() { std::cout << "B constructor" << std::endl; }
~B() { std::cout << "B destructor" << std::endl; }
void setA(std::shared_ptr<A> a) { ptrA = a; }
};
// 循环引用示例
void demonstrate_circular_reference() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();
a->setB(b);
b->setA(a);
// 当a和b离开作用域时,它们的引用计数都无法降到0
// 导致A和B的析构函数都不会被调用,内存泄漏
}为了解决这个问题,我们将其中一个
shared_ptr
weak_ptr
weak_ptr
B
A
weak_ptr
立即学习“C++免费学习笔记(深入)”;
#include <iostream>
#include <memory>
class B_fixed; // 前向声明
class A_fixed {
public:
std::shared_ptr<B_fixed> ptrB;
A_fixed() { std::cout << "A_fixed constructor" << std::endl; }
~A_fixed() { std::cout << "A_fixed destructor" << std::endl; }
void setB(std::shared_ptr<B_fixed> b) { ptrB = b; }
};
class B_fixed {
public:
std::weak_ptr<A_fixed> ptrA; // 关键改变:使用weak_ptr
B_fixed() { std::cout << "B_fixed constructor" << std::endl; }
~B_fixed() { std::cout << "B_fixed destructor" << std::endl; }
void setA(std::shared_ptr<A_fixed> a) { ptrA = a; }
// 访问ptrA时需要先lock()
void accessA() {
if (auto sharedA = ptrA.lock()) { // 尝试获取shared_ptr
std::cout << "A_fixed object still exists and is accessible." << std::endl;
} else {
std::cout << "A_fixed object no longer exists." << std::endl;
}
}
};
// 解决循环引用后的示例
void demonstrate_no_circular_reference() {
std::shared_ptr<A_fixed> a = std::make_shared<A_fixed>();
std::shared_ptr<B_fixed> b = std::make_shared<B_fixed>();
a->setB(b);
b->setA(a);
// 当a和b离开作用域时:
// 1. a的引用计数为1 (外部持有a)
// 2. b的引用计数为1 (a->ptrB持有b)
// 3. b->ptrA (weak_ptr) 不增加a的引用计数
// 当a离开作用域时,a的引用计数从1变为0,A_fixed析构
// 此时b->ptrA失效
// 当b离开作用域时,b的引用计数从1变为0,B_fixed析构
// 内存得到正确释放
}
int main() {
std::cout << "--- Demonstrating circular reference (will leak) ---" << std::endl;
demonstrate_circular_reference();
std::cout << "--- End of circular reference demo ---" << std::endl << std::endl;
std::cout << "--- Demonstrating no circular reference with weak_ptr ---" << std::endl;
demonstrate_no_circular_reference();
std::cout << "--- End of no circular reference demo ---" << std::endl;
return 0;
}运行上述
main
demonstrate_circular_reference
demonstrate_no_circular_reference
weak_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
问题就出在这里:如果两个或更多个对象,通过
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
weak_ptr
shared_ptr
weak_ptr
shared_ptr
这就意味着,即使存在一个
weak_ptr
shared_ptr
weak_ptr
那么,我们如何通过
weak_ptr
weak_ptr
lock()
lock()
shared_ptr
shared_ptr
lock()
shared_ptr
shared_ptr
lock()
shared_ptr
weak_ptr
父子/层级关系中子节点引用父节点: 这是一个非常经典的场景。比如一个UI控件(子)需要访问它的父容器(父),但父容器才是真正管理子控件生命周期的。如果子控件持有父容器的
shared_ptr
weak_ptr
weak_ptr
观察者模式(Observer Pattern): 在事件驱动或观察者模式中,一个被观察者(Subject)可能需要持有多个观察者(Observer)的列表。如果被观察者持有观察者的
shared_ptr
shared_ptr
weak_ptr
weak_ptr
缓存管理: 在一些缓存系统中,你可能希望缓存中的对象在没有其他地方引用它们时自动过期。如果缓存直接持有对象的
shared_ptr
weak_ptr
shared_ptr
weak_ptr
大型数据结构中的节点回溯: 想象一个图结构或者复杂的树,节点可能需要引用其邻居或父节点。如果所有引用都是
shared_ptr
weak_ptr
选择
weak_ptr
lock()
shared_ptr
if (auto shared_ptr_obj = weak_ptr_obj.lock())
以上就是C++shared_ptr与weak_ptr结合解决循环引用的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号