改進物件池模式
物件池對於建立開銷比較大的物件來說很有意義,為了避免重複建立開銷比較大的物件,可以通過物件池來優化。物件池的思路比較簡單,事先建立好一批物件,放到乙個集合中,每當程式需要新的物件時,就從物件池中獲取,程式用完該物件後都會把該物件歸還給物件池。這樣會避免重複建立物件,提高程式效能。物件池的實現如**清單8-12所示。
#include
#include
#include
#include
using
namespace std;
const
int maxobjectnum =10;
template
<
typename t>
class
objectpool
~objectpool()
// 預設建立多少個物件
template
<
typename..
. args>
void
init
(size_t num, args&&..
. args)))
;}}template
<
typename t,
typename..
. args>
std::shared_ptr
createptr
(std::string& constructname, args.
.. args));
}// 從物件池中獲取乙個物件
template
<
typename..
. args>
std::shared_ptr
get(
)return
nullptr;}
private
:std::multimap> m_object_map;
bool needclear;};
這個物件池的實現很典型:初始建立一定數量的物件,用的時候直接從
池中取,用完之後再**到池子。
一般物件池的實現思路和這個類似,這種實現方式雖然能達到目的,但是存在以下不足:
1)物件用完之後需要手動**,用起來不夠方便,更大的問題是存在忘
記**的風險。
2)不支援引數不同的建構函式。
通過c++11可以解決這兩個問題:
1)對於第乙個問題,通過自動**用完的物件來解決。這裡用智慧型指標
就可以解決,在建立智慧型指標時可以指定刪除器,在刪除器中不刪除物件,
而是將其**到物件池中。這個過程對外界來說是看不見的,由智慧型指標自
己完成。
2)對於第二個問題,通過可變引數模板來解決。可變引數模板可以支援
不同引數的建構函式來建立物件。
物件池的實現如**清單8-13所示:
#include
#include
#include
#include
#include
"noncopyable.hpp"
usingnamespace std;
const
int maxobjectnum =10;
template
classobjectpool : noncopyable))
;}}// 從物件池中獲取乙個物件
template
<
typename..
. args>
std::shared_ptr
get(
)return
nullptr;}
private
:multimap> m_object_map;
};
測試**如**清單8-14所示:
#include
struct bigobject
bigobject
(int a)
bigobject
(const
int& a,
const
int& b)
void
print
(const string& str)};
void
print
(shared_ptrp,
const string& str)
}void
testobjpool()
// 出了作用域之後,物件池返回出來的物件又會自動**
auto p = pool.
get();
auto p2 = pool.
get();
print
(p,"p");
print
(p2,
"p2");
// 物件池支援過載建構函式
pool.
init(2
,1);
auto p4 = pool.get<
int>()
;print
(p4,
"p4");
pool.
init(2
,1,2
);auto p5 = pool.get<
int,
int>()
;print
(p5,
"p5");
}int
main()
輸出結果如下:pp2
pp2p4p5
在上述測試**中,設定了物件池的最大容量為2,所以在獲取p3時,將獲得乙個空指標。在離開作用域之後物件就被物件池**,後面就能再獲取池中的物件了。這裡需要注意的是,物件被**之後它的狀態並沒有被清除,使用者從池中獲取物件之後最好先初始化或重置一下狀態。p4和p5是不同建構函式建立的物件。需要注意的是,在物件池中建立不同的物件時,建構函式入參的引用將被忽略,即入參int和int&的建構函式會被認為是同一種型別的建構函式,因為在構造物件時無法獲取變參args…的引用型別,丟失了引用相關的資訊。
相比傳統的實現方式,改進之後的物件池的實現不僅能自動**物件,還能支援引數不同的建構函式,更加靈活和強大。
深入理解C 11(九)
move語義 我們知道移動語義是通過右值引用來匹配臨時值的,那麼,普通的左值是否也能借助移動語義來優化效能呢,那該怎麼做呢?事實上c 11為了解決這個問題,提供了std move方法來將左值轉換為右值,從而方便應用移動語義。move是將物件的狀態或者所有權從乙個物件轉移到另乙個物件,只是轉移,沒有記...
深入理解C 11(十五)
emplace back減少記憶體拷貝和移動 emplace back能就地通過引數構造物件,不需要拷貝或者移動記憶體,相比push back能更好地避免記憶體的拷貝與移動,使容器插入元素的效能得到進一步提公升。在大多數情況下應該優先使用emplace back來代替push back。所有的標準庫...
深入理解C 11(十六)
unordered container無序容器 c 11增加了無序容器unordered map unordered multimap和unordered set unordered multiset,由於這些容器中的元素是不排序的,因此,比有序容器map multimap和set multiset...