weak_ptr通过不增加引用计数的非拥有引用打破shared_ptr循环引用,当对象仅被weak_ptr指向时仍可被释放,从而避免内存泄漏。

在C++中,
weak_ptr
shared_ptr
shared_ptr
shared_ptr
weak_ptr
#include <iostream>
#include <memory>
#include <vector>
class NodeA; // 前向声明
class NodeB {
public:
std::shared_ptr<NodeA> parent; // 强引用,如果NodeA也强引用NodeB,就会形成循环
NodeB() { std::cout << "NodeB 构造\n"; }
~NodeB() { std::cout << "NodeB 析构\n"; }
void setParent(std::shared_ptr<NodeA> p) {
parent = p;
}
};
class NodeA {
public:
std::weak_ptr<NodeB> child; // 使用 weak_ptr 解决循环引用
NodeA() { std::cout << "NodeA 构造\n"; }
~NodeA() { std::cout << "NodeA 析构\n"; }
void setChild(std::shared_ptr<NodeB> c) {
child = c; // weak_ptr 不增加引用计数
}
void accessChild() {
if (auto strongChild = child.lock()) { // 尝试获取 shared_ptr
std::cout << "NodeA 成功访问到 NodeB 子节点。\n";
} else {
std::cout << "NodeA 尝试访问 NodeB 失败,子节点已销毁。\n";
}
}
};
// 模拟循环引用场景,并展示 weak_ptr 的解决方案
void demonstrate_circular_reference() {
std::cout << "--- 演示 weak_ptr 解决循环引用 ---\n";
std::shared_ptr<NodeA> nodeA_ptr = std::make_shared<NodeA>();
std::shared_ptr<NodeB> nodeB_ptr = std::make_shared<NodeB>();
std::cout << "初始化后: NodeA 引用计数 = " << nodeA_ptr.use_count()
<< ", NodeB 引用计数 = " << nodeB_ptr.use_count() << "\n";
nodeA_ptr->setChild(nodeB_ptr); // NodeA 弱引用 NodeB
nodeB_ptr->setParent(nodeA_ptr); // NodeB 强引用 NodeA
std::cout << "设置引用后: NodeA 引用计数 = " << nodeA_ptr.use_count()
<< ", NodeB 引用计数 = " << nodeB_ptr.use_count() << "\n";
nodeA_ptr->accessChild();
// 当 nodeA_ptr 和 nodeB_ptr 超出作用域时
// NodeB 的 parent 强引用 NodeA,NodeA 的引用计数为 1
// NodeA 的 child 弱引用 NodeB,NodeB 的引用计数为 1
// 由于 NodeB 的 parent 强引用 NodeA,NodeA 无法析构
// 同样,NodeA 的 child 是弱引用,不影响 NodeB 析构
// 但 NodeB 的强引用 NodeA 导致 NodeA 无法析构,进而导致 NodeB 也无法析构 (如果NodeA强引用NodeB,NodeB强引用NodeA)
// 在这个例子中,NodeA 使用了 weak_ptr,所以 NodeB 的 parent 是唯一强引用 NodeA 的
// 当 nodeA_ptr 超出作用域,NodeA 的引用计数会变为 1 (来自 NodeB 的 parent)
// 当 nodeB_ptr 超出作用域,NodeB 的引用计数会变为 0,NodeB 析构
// NodeB 析构时,其 parent (指向 NodeA) 的 shared_ptr 也被释放,NodeA 的引用计数变为 0,NodeA 析构。
// 完美解决!
std::cout << "shared_ptr 离开作用域...\n";
}
// int main() {
// demonstrate_circular_reference();
// std::cout << "--- 演示结束 ---\n";
// return 0;
// }shared_ptr
在我看来,
shared_ptr
shared_ptr
shared_ptr
具体来说,
shared_ptr
shared_ptr
shared_ptr
循环引用发生时,例如对象A持有一个指向对象B的
shared_ptr
shared_ptr
shared_ptr
立即学习“C++免费学习笔记(深入)”;
weak_ptr
shared_ptr
weak_ptr
shared_ptr
weak_ptr
它的具体机制在于:
shared_ptr
weak_ptr
shared_ptr
weak_ptr
shared_ptr
weak_ptr
weak_ptr
weak_ptr::lock()
lock()
weak_ptr
shared_ptr
shared_ptr
lock()
shared_ptr
shared_ptr
shared_ptr
lock()
shared_ptr
nullptr
lock()
weak_ptr
expired()
expired()
true
weak_ptr
shared_ptr
shared_ptr
shared_ptr
weak_ptr
正是这种非拥有特性,使得
weak_ptr
shared_ptr
weak_ptr
weak_ptr
在实际项目中,
weak_ptr
常见的应用场景:
Parent
Child
Parent
shared_ptr
Child
Child
Parent
Child
shared_ptr
Parent
Child
Parent
weak_ptr
Child
Parent
Parent
class Parent;
class Child {
public:
std::weak_ptr<Parent> parent; // 子节点弱引用父节点
// ...
};
class Parent {
public:
std::vector<std::shared_ptr<Child>> children; // 父节点强引用子节点
// ...
};shared_ptr
shared_ptr
weak_ptr
weak_ptr
weak_ptr
使用注意事项:
lock()
weak_ptr
weak_ptr
lock()
shared_ptr
if (auto strong_ptr = weak_ptr_instance.lock()) {
// 对象仍然存在,可以安全使用 strong_ptr
strong_ptr->do_something();
} else {
// 对象已销毁
std::cout << "对象已销毁,无法访问。\n";
}lock()
lock()
weak_ptr
weak_ptr
shared_ptr
weak_ptr
weak_ptr
lock()
nullptr
lock()
weak_ptr
shared_ptr
weak_ptr
lock()
在我看来,
weak_ptr
shared_ptr
weak_ptr
以上就是C++weak_ptr解决循环引用问题技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号