【C++11】實現物件池
阿新 • • 發佈:2019-02-05
物件池
物件池顧名思義,就是存放一堆物件的池,目前一般的實現方式大多都是如下思路:
- 初始化建立一些系列(或者從外部載入)
- 從物件池取出一個物件使用
- 用完之後返回物件池
物件池有很多場景都可以使用,例如:一個物件構造很消耗時間,又或者一些物件被很頻繁的使用,都可以使用物件池。它的思想類似於資料庫連線池、網路控制代碼連線池等等。
在C++中藉助智慧指標,可以很方便的實現一個物件池,智慧指標可以自定義刪除器,在智慧指標需要釋放的時候呼叫刪除器,將物件重新放入物件池。
這裡關鍵要注意:
- 自定義刪除器
- shared_ptr或者unique_ptr
細節
自定義刪除器只做一件事,就是將物件重新放入物件池。如果物件池初始化的時候就自定義刪除器的話,刪除器中的邏輯是將物件放回物件池,放回的時候無法再定義一個這樣的刪除器,所以這種做法行不通。
需要注意,回收的物件只能是預設刪除器的。除了前述原因之外,另外一個原因是物件池釋放的時候需要釋放所有的智慧指標,釋放的時候如果存在自定義刪除器將會導致物件無法刪除。
只有在get的時候定義刪除器才行,但是初始建立或加入的智慧指標是預設刪除器,所以我們需要把智慧指標的預設刪除器改為自定義刪除器。
因為我們需要把智慧指標的預設刪除器改為自定義刪除器,用shared_ptr會很不方便,因為你無法直接將shared_ptr的刪除器修改為自定義刪除器,雖然你可以通過重新建立一個新物件,把原物件拷貝過來的做法來實現,但是這樣做效率比較低。而unique_ptr由於是獨佔語義,提供了一種簡便的方法方法可以實現修改刪除器,所以用unique_ptr是最合適的。
程式碼實現
template<class T>
class SimpleObjectPool
{
public:
using DelType = std::function<void(T*)>;
void add(std::unique_ptr<T> t)
{
m_pool.push_back(std::move(t));
}
std::unique_ptr<T, DelType> get()
{
if (m_pool.empty())
{
throw std::logic_error("no object");
}
//every time add custom deleter for default unique_ptr
std::unique_ptr<T, DelType> ptr(m_pool.back().release(), [this](T* t)
{
m_pool.push_back(std::unique_ptr<T>(t)); //刪除函式執行的操作
});
m_pool.pop_back(); //刪除最後一個被釋放的unique_ptr
return std::move(ptr);
}
bool empty() const
{
return m_pool.empty();
}
int size() const
{
return m_pool.size();
}
private:
std::vector<std::unique_ptr<T>> m_pool;
};
//測試物件
struct STA
{
STA()
{
cout << "create" << endl;
}
STA(int i)
{
a = i;
cout << "create int" << endl;
}
STA(const STA& other)
{
*this = other;
cout << "copy" << endl;
}
~STA()
{
cout << "delete" << endl;
}
int a = 0;
};
//測試程式碼
void testPool()
{
SimpleObjectPool<STA> pool;
pool.add(std::unique_ptr<STA>(new STA()));
pool.add(std::unique_ptr<STA>(new STA()));
{
auto ptr = pool.get();
pool.get();
cout <<"pool size:"<< pool.size() << endl;
}
cout << "pool size:" << pool.size() << endl;
{
pool.get();
pool.get();
cout << "pool size:" << pool.size() << endl;
}
cout << "pool size:" << pool.size() << endl;
}
輸出如下: