在C++中,智能指针为我们提供了自动管理内存的机制,尤其是 std::shared_ptr。但在某些情况下,多个对象之间的互相引用会导致循环引用问题,从而使对象的析构函数无法调用,导致内存泄漏。
1. 代码
#include <iostream>
#include <memory>
using namespace std;
class A;
class B {
public:
std::shared_ptr<A> ptr_a;
~B() {
std::cout << "B has been destructured " << endl;
}
};
class A {
public:
// std::shared_ptr<B> ptr_b;
std::weak_ptr<B> ptr_b; // 使用 weak_ptr 打破循环引用
~A() {
std::cout << "A has been destructured" << endl;
}
};
int main() {
auto ptr_B = std::make_shared<B>();
auto ptr_A = std::make_shared<A>();
ptr_B->ptr_a = ptr_A;
ptr_A->ptr_b = ptr_B;
cout << "ptr_A: " << ptr_A.use_count() << endl;
cout << "ptr_B: " << ptr_B.use_count() << endl;
return 0;
}
2. 当两个都使用 std::shared_ptr 时
-
当执行 auto ptr_B = std::make_shared(); 时,ptr_B 指向 B,此时 B 的引用计数为 1。
-
当执行 auto ptr_A = std::make_shared(); 时,ptr_A 指向 A,此时 A 的引用计数为 1。
-
接下来,两者互相引用:
ptr_B->ptr_a = ptr_A;使 B 对象的 ptr_a 持有 A 对象的 ptr_A,A 的引用计数增加到 2(ptr_A,B::ptr_a)。ptr_A->ptr_b = ptr_B; 使 A 对象的 ptr_b 持有 B 对象的 ptr_B,B 的引用计数增加到 2(ptr_B,A::ptr_b)。
-
当 main 函数结束时,ptr_A 和 ptr_B 超出作用域,引用计数分别从 2 减少到 1,但由于它们互相持有对方的 shared_ptr,引用计数无法归零,因此不会调用析构函数,导致内存泄漏。
2.1 程序运行结果

3. 当其中一方使用 std::weak_ptr 时
std::weak_ptr 是一种弱引用,不会增加引用计数。通过将 A 持有的 ptr_b 改为 std::weak_ptr,可以打破循环引用,确保对象能正常析构。
- 当执行
auto ptr_B = std::make_shared<B>();时,ptr_B 指向 B,此时 B 的引用计数为 1。 - 当执行
auto ptr_A = std::make_shared<A>(); 时,ptr_A 指向 A,此时 A 的引用计数为 1。 - 接下来,两者互相引用:
ptr_B->ptr_a = ptr_A; 使 B 的 ptr_a 持有 A 对象的 ptr_A,A 的引用计数增加到 2。ptr_A->ptr_b = ptr_B;使用 weak_ptr,这不会增加 B 的引用计数,因此 B 的引用计数仍为 1。
- 当 main 函数结束时:ptr_A 和 ptr_B 超出作用域,引用计数减少:
- A 的引用计数从 1 变为 0,A 被析构,输出 “
A has been destructured”。 - 在 A 的析构过程中,A::ptr_b 被销毁,B 的引用计数从 2 变为 1。
- B 的引用计数从 1 变为 0,B 被析构,输出 “
B has been destructured”。
这样,A 和 B 都被正确析构,没有内存泄漏。
- A 的引用计数从 1 变为 0,A 被析构,输出 “
3.1 程序运行结果

1352

被折叠的 条评论
为什么被折叠?



