1. 程式人生 > >C++利用智慧指標shared_ptr實現物件池

C++利用智慧指標shared_ptr實現物件池

         C++中用new來分配物件,還要顯式的呼叫delete來析構物件,很容易造成記憶體洩露。所以在研究我們遊戲伺服器的程式碼的時候發現,我們將new函式封裝,在物件池上,利用shared_ptr的特性來自動釋放物件,同時實現了一種簡單的GC回收物件的機制。看完之後,覺得搞的不錯,這樣很容易管理專案中new。所以把相關程式碼分享一下。

        首先說下基本思路,物件池,其實就是個vector,裡面放的是pair<shared_ptr<T>,bool> ,也就是放的是一個鍵值對,鍵為智慧指標物件,值為一個bool值,標誌池子中這個物件有木有被引用。

        接著說下過程,第一次使用New來建立物件的時候,我們看下池子裡面有木有這種物件,沒有的話,就直接在池子裡生成一定數目的此型別物件,然後將對應的bool值設定為true,標誌著當前這個位置可以用。然後我們從池子最後面去一個出來,將bool值設定為false,將shared_ptr的值拿出來賦給我們要生成的物件,那麼此時,池子裡,對應這個位置上的shared_ptr物件,就有兩個引用了,一個是池子自身物件,一個是我們新生成的物件,理解這個很關鍵,如果不理解可以去單獨看下,shared_ptr這個解釋,例子裡會有相關的解釋跟用法。另外如果池子物件都滿了怎麼辦了,那麼就擴大池子為原來的2倍,重新分配。

        最後何時去析構對應的物件呢?我們主tick中,看看,當前池子中那些位置被引用了,然後看看這些位置對應的只能指標是不是唯一,如果唯一,說明只有池子裡的物件在引用它,那麼就可以將這個物件中存的資料給析構掉,重新分配一個物件放進去,並且置該位置為true標誌當前位置可用。

下面的程式碼簡單的模擬了,下物件池的過程,還有很多細節都沒有處理,只是示意一般的過程,對於理解已經足夠了。

#include "stdafx.h"
#include <boost/lexical_cast.hpp>  
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <vector>
using namespace std;
//測試類
class test
{
public:
	test();
	~test();

private:

};

test::test()
{
	cout << "test is created! " << endl;
}

test::~test()
{
	cout << "test is destroyed! " << endl;
}
//元素智慧指標
typedef boost::shared_ptr<test> _ElemPtr;

//元素鍵值對
typedef std::pair<_ElemPtr,bool> _ElemUnit;

//物件池
typedef vector<_ElemUnit> _ElemCont;

//定義物件池
_ElemCont m_elemCount;

//測試函式
void testPrint()
{
	//new一個物件,相當於從物件池最後取出一個物件
	_ElemPtr elemPtr = m_elemCount[7].first;

	//物件池,該位置置為false
	m_elemCount[7].second = false;
	cout << "m_elemCount[7] === " << m_elemCount[7].first.unique() << endl;

	cout << "m_elemCount[7].usecount == " << m_elemCount[7].first.use_count() << endl;
	return ;
}
int main()
{
	//初始化一個型別為test的物件池
	for(int i = 0; i < 8; i++)
	{
		_ElemPtr elemPtr(new test());
		m_elemCount.push_back(std::make_pair(elemPtr,true));
	}

	//檢測下當前物件池最後一個元素是否被引用
	if(m_elemCount[7].first.unique())
	{
		cout << "m_eleCount[7] is unique()" << endl;
	}

	//_ElemPtr elemPtr = m_elemCount[7].first;

	//模擬生成一個物件,然後又銷燬
	testPrint();

	cout << "m_elemCount[7] === " << m_elemCount[7].first.unique() << endl;

	//模擬回收過程,如果物件池這個位置被引用過
	if(!m_elemCount[7].second)
	{
		//看看這個物件引用是否唯一,是否只有一個,只有一個的話,就GC
		if(m_elemCount[7].first.unique())
		{
			m_elemCount[7].first->~test();
		}
	}

	getchar();
	return 0;
}