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; }