關(guān)于shared_ptr的內(nèi)存泄漏
結(jié)論:
- 當(dāng)對象存在循環(huán)引用時,shared_ptr存在內(nèi)存泄漏;
- 標(biāo)準(zhǔn)庫提供了weak_ptr來解決,通過weak_ptr去引用對象,不會增加對象的引用計數(shù);
#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計數(shù)器 1
//分配了一塊內(nèi)存大小是sizeof(A), 假設(shè)該內(nèi)存的地址是ptr_A
//該內(nèi)存由一個共享指針shared_ptr aa來管理,怎么管理呢?
//維護了ptr_A這塊內(nèi)存的引用計數(shù);截止到目前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計數(shù)器 1
//分析同上,ptr_B的ref_count是1
cout << "bb's ref_count=" << bb.use_count() << endl;
aa->b = bb;// bb 計數(shù)器來到了 2
//上述操作之后,ptr_B這塊內(nèi)存通過aa->b也可以訪問到了,也就是ptr_B的引用計數(shù)變到了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 計數(shù)器來到了 2
//上述操作之后,ptr_A這塊內(nèi)存通過bb->a也可以訪問到了,也就是ptr_A的引用計數(shù)變到了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;
//析構(gòu)函數(shù)開始執(zhí)行
//首先要釋放的是bb, ptr_B的引用計數(shù)減1到了1;所以ptr_B指向的B對象還不能釋放
//然后要釋放的是aa, ptr_A的引用計數(shù)減1到了1;所以ptr_A指向的A對象還不能釋放
//然后就內(nèi)存泄漏了
具體輸出如下:
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 計數(shù)器來到了 2
//假設(shè)如果沒有bb->a=aa這個操作,也就說沒有循環(huán)引用;
//析構(gòu)函數(shù)開始執(zhí)行
//首先要釋放的是bb, ptr_B的引用計數(shù)減1到了1;所以ptr_B指向的B對象還不能釋放
//然后要釋放的是aa, ptr_A的引用計數(shù)減1到了0;所以ptr_A指向的A對象可以釋放了
//前面aa對象釋放時,內(nèi)部的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;
}