关于shared_ptr的内存泄漏
结论:
- 当对象存在循环引用时,shared_ptr存在内存泄漏;
- 标准库提供了weak_ptr来解决,通过weak_ptr去引用对象,不会增加对象的引用计数;
#include <iostream>
#include <memory>
using namespace std;
class B;
class A
{
public:
A() { cout << "A's constructor ..." << endl; }
~A() { cout << "A's destructor ..." << endl; }
std::shared_ptr<B> b;//class A中含有指向class B的shared指针
};
class B
{
public:
B() { cout << "B's constructor ..." << endl; }
~B() { cout << "B's destructor ..." << endl; }
std::shared_ptr<A> a; //class B 中含有指向class A的shared指针
};
int main()
{
std::shared_ptr<A> aa = make_shared<A>(); //aa->object A aa计数器 1
//分配了一块内存大小是sizeof(A), 假设该内存的地址是ptr_A
//该内存由一个共享指针shared_ptr aa来管理,怎么管理呢?
//维护了ptr_A这块内存的引用计数;截止到目前ptr_A就aa一个对象持有;所以ptr_A的ref_count是1
cout << "aa's ref_count=" << aa.use_count() << endl;
std::shared_ptr<B> bb = make_shared<B>(); //bb->object B bb计数器 1
//分析同上,ptr_B的ref_count是1
cout << "bb's ref_count=" << bb.use_count() << endl;
aa->b = bb;// bb 计数器来到了 2
//上述操作之后,ptr_B这块内存通过aa->b也可以访问到了,也就是ptr_B的引用计数变到了2
cout << "after aa->b = bb, aa's ref_count=" << aa.use_count() << "," << "aa.b's ref_count=" << aa->b.use_count() << ",";
cout << "bb's ref_count=" << bb.use_count() << endl;
/*
bb->a = aa;// aa 计数器来到了 2
//上述操作之后,ptr_A这块内存通过bb->a也可以访问到了,也就是ptr_A的引用计数变到了2
cout << "after bb->a = aa, aa's ref_count=" << aa.use_count() << "," << "bb.a's ref_count=" << bb->a.use_count() << ",";
cout << "bb's ref_count=" << bb.use_count() << endl;
//析构函数开始执行
//首先要释放的是bb, ptr_B的引用计数减1到了1;所以ptr_B指向的B对象还不能释放
//然后要释放的是aa, ptr_A的引用计数减1到了1;所以ptr_A指向的A对象还不能释放
//然后就内存泄漏了
具体输出如下:
A's constructor ...
aa's ref_count=1
B's constructor ...
bb's ref_count=1
after aa->b = bb, aa's ref_count=1,aa.b's ref_count=2,bb's ref_count=2
after bb->a = aa, aa's ref_count=2,bb.a's ref_count=2,bb's ref_count=2
*/
/*
//bb->a = aa;// aa 计数器来到了 2
//假设如果没有bb->a=aa这个操作,也就说没有循环引用;
//析构函数开始执行
//首先要释放的是bb, ptr_B的引用计数减1到了1;所以ptr_B指向的B对象还不能释放
//然后要释放的是aa, ptr_A的引用计数减1到了0;所以ptr_A指向的A对象可以释放了
//前面aa对象释放时,内部的b也同时被销毁,ptr_B的ref_count减到了0,ptr_B也可以释放了
具体输出如下:
A's constructor ...
aa's ref_count=1
B's constructor ...
bb's ref_count=1
after aa->b = bb, aa's ref_count=1,aa.b's ref_count=2,bb's ref_count=2
A's destructor ...
B's destructor ...
*/
return 0;
}