C++中shared_ptr循环引用因相互持有导致引用计数无法归零,引发内存泄漏;解决方法是使用std::weak_ptr打破循环,如子节点用weak_ptr引用父节点,避免增加引用计数,从而确保对象可正常析构。

C++中
shared_ptr
shared_ptr
std::weak_ptr
解决
shared_ptr
std::weak_ptr
shared_ptr
weak_ptr
weak_ptr
考虑一个典型的父子关系或节点关系:
#include <iostream>
#include <memory>
#include <vector>
class Child; // 前向声明
class Parent {
public:
std::string name;
std::vector<std::shared_ptr<Child>> children;
Parent(std::string n) : name(n) {
std::cout << "Parent " << name << " created." << std::endl;
}
~Parent() {
std::cout << "Parent " << name << " destroyed." << std::endl;
}
void addChild(std::shared_ptr<Child> child);
};
class Child {
public:
std::string name;
std::weak_ptr<Parent> parent; // 使用 weak_ptr 引用父对象
Child(std::string n) : name(n) {
std::cout << "Child " << name << " created." << std::endl;
}
~Child() {
std::cout << "Child " << name << " destroyed." << std::endl;
}
void setParent(std::shared_ptr<Parent> p) {
parent = p;
}
void greetParent() {
if (auto p_locked = parent.lock()) { // 尝试锁定 weak_ptr 为 shared_ptr
std::cout << "Child " << name << " greets Parent " << p_locked->name << std::endl;
} else {
std::cout << "Child " << name << ": Parent is gone." << std::endl;
}
}
};
void Parent::addChild(std::shared_ptr<Child> child) {
children.push_back(child);
child->setParent(std::shared_ptr<Parent>(this, [](Parent*){})); // 注意这里,避免创建新的 shared_ptr 拥有 Parent
// 更安全的做法是:在创建 Parent 时就使用 shared_ptr,然后将 Parent 的 shared_ptr 传递给 Child
// 例如:std::shared_ptr<Parent> p = std::make_shared<Parent>("Father");
// std::shared_ptr<Child> c = std::make_shared<Child>("Son");
// p->addChild(c); // 此时 Child 内部可以通过 p 构造 weak_ptr
}
// 修正后的 Parent::addChild,更符合实际场景,需要 Parent 自身也是 shared_ptr
void Parent_Corrected_AddChild(std::shared_ptr<Parent> self, std::shared_ptr<Child> child) {
self->children.push_back(child);
child->setParent(self); // Child 现在通过 weak_ptr 引用这个 shared_ptr<Parent>
}
int main() {
std::cout << "--- Scenario with cyclic reference (if not using weak_ptr) ---" << std::endl;
// 如果 Child::parent 也是 shared_ptr,这里会发生内存泄漏
// std::shared_ptr<Parent> p1 = std::make_shared<Parent>("P1");
// std::shared_ptr<Child> c1 = std::make_shared<Child>("C1");
// p1->children.push_back(c1);
// c1->parent = p1; // 此时 p1 和 c1 互相持有,引用计数永远不为0
std::cout << "--- Scenario with weak_ptr ---" << std::endl;
std::shared_ptr<Parent> p2 = std::make_shared<Parent>("P2");
std::shared_ptr<Child> c2 = std::make_shared<Child>("C2");
// Parent_Corrected_AddChild(p2, c2); // 假设我们有这样一个辅助函数
p2->children.push_back(c2);
c2->setParent(p2); // Child 通过 weak_ptr 引用 Parent
c2->greetParent();
// 当 p2 和 c2 离开作用域时,它们会被正确销毁
std::cout << "--- Exiting main scope ---" << std::endl;
return 0;
}在上面的例子中,
Child
std::weak_ptr<Parent> parent
Parent
Child
parent.lock()
nullptr
立即学习“C++免费学习笔记(深入)”;
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
循环引用,顾名思义,就是两个或多个
shared_ptr
shared_ptr
shared_ptr
shared_ptr
shared_ptr
识别
shared_ptr
一个最直接的信号是:当你预期某个对象应该被销毁,但它的析构函数(如果你有打印日志)却迟迟没有被调用。这通常表明它的引用计数没有归零。
在开发阶段,可以采取几种策略来主动检测:
weak_ptr
memcheck
shared_ptr
shared_ptr
shared_ptr
shared_ptr
在我自己的经验里,很多时候是先通过内存分析工具发现有泄漏,然后回溯代码,在可疑的相互引用点进行仔细的代码审查,最终定位到循环引用的。这通常是一个迭代的过程,需要耐心。
weak_ptr
虽然
weak_ptr
shared_ptr
shared_ptr
shared_ptr
std::vector<std::unique_ptr<Button>>
weak_ptr
shared_ptr
unique_ptr
weak_ptr
shared_ptr
weak_ptr
weak_ptr
shared_ptr
enable_shared_from_this
shared_ptr
unique_ptr
weak_ptr
这些策略并非相互排斥,而是可以结合使用,共同构建一个健壮、无内存泄漏的C++应用。关键在于,在设计阶段就深入思考对象间的关系和生命周期,而不是等到问题出现再去修补。
以上就是C++shared_ptr循环引用检测与解决技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号