循環引用-智能指針的死穴之一

       智能指針的實現思路也體現了C++基於對象的原則,對象應該爲自己管理的資源負責,包括資源的分配與釋放,而且最好將資源的釋放與分配搞的自動化一點,典型的實現方法就是在構造函數裏分配資源,在析構函數裏釋放資源,這樣當其他程序員在使用這個對象時,該對象的資源問題幾乎不用額外的操心,即優雅又方便

        然後如此完美的東西,也有其不容忽視的地方,直接上代碼:

// share_ptr.cpp : 定義控制檯應用程序的入口點。
//

#include "stdafx.h"
#include "common_class.h"

class B;

class A{

private:
	typedef tr1::shared_ptr<B> Item_Type;
public:
	explicit A(){};
	virtual ~A(){};

public:
	void SetB(const Item_Type ptr_B){m_B = ptr_B;}
private:
	Item_Type m_B;
};

class B{

private:
	typedef tr1::shared_ptr<A> Item_Type;
public:
	explicit B(){};
	virtual ~B(){};
public:
	void SetA(const Item_Type ptr_A){m_A = ptr_A;}
private:
	Item_Type m_A;
};
int _tmain(int argc, _TCHAR* argv[])
{
	size_t count = 100000;
	getchar();//查看內存狀態
	while(count--)
	{
		//new出來的A的引用計數此時爲1
		shared_ptr<A> a(new A);
		//new出來的A的引用計數此時爲1
		shared_ptr<B> b(new B);

		//B的引用計數增加爲2
		a->SetB(b);
		//A的引用計數增加爲2
		b->SetA(a);
	}
	getchar();//查看內存狀態

	//b先出作用域,B的引用計數減少爲1,不爲0,所以堆上的B空間沒有被釋放,
	//且B持有的A也沒有機會被析構,A的引用計數也完全沒減少
	//a後出作用域,同理A的引用計數減少爲1,不爲0,所以堆上A的空間也沒有被釋放
	return 0;
}

 

兩次查看內存資源狀態結果

圖像1

結果可知:內存增加了幾乎20M,更何況我定義的兩個對象本身不怎麼佔資源,如果內部維護了幾個list,結果可想而知!

A和B都互相指着對方吼,“放開我的引用!“,“你先發我的我就放你的!”,於是悲劇發生了。

所以在使用基於引用計數的智能指針時,要特別小心循環引用帶來的內存泄漏,循環引用不只是兩方的情況,只要引用鏈成環都會出現問題。當然循環引用本身就說明設計上可能存在一些問題,如果特殊原因不得不使用循環引用,那可以讓引用鏈上的一方持用普通指針(或弱智能指針weak_ptr)即可.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章