在实际中,我们会遇到一个类最多只允许若干个对象同时存在的情形。如果这个类的对象会被频繁的创建,使用并销毁,那这时会对系统性能造成影响,而这时可以考虑使用对象池的方法来避免每次使用对象都需要从“构造->使用->销毁”这个流程,对象池中的每个对象都一次构造多次使用,而析构也只会在对象池析构是才会发生。
要实现对象池,那关键问题就在于如果在对象析构时不是真正的析构,而是重新回到对象池中。假如我们每次从对象池中取到的对象都是对象本身,那我们则无法让对象在需要析构时重新回到对象池,所以我们只能返回一个管理对象,这个管理对象实际管理者我们的实际对象,在它析构时它将实际的对象归还到对象池中。那最好的选择就是每次都返回一个只能指针比如std::unique_ptr,我们在返回这个只能指针时,将其析构函数修改为将对象归还至对象池,而非直接析构,这样就可以实现对象回收了。下面来直接看代码:
#pragma once
#include <memory>
#include <vector>
#include <functional>
#include <thread>
using std::unique_ptr;
using std::vector;
using std::function;
using std::mutex;
template<typename T>
class ObjectPool
{
using deleter = std::function<void(T*)>;
public:
ObjectPool() = default;
~ObjectPool() = default;
void addObject(unique_ptr<T> objPtr)
{
std::unique_lock<std::mutex> ul(objObtainLock);
objCont.emplace_back(std::move(objPtr));
}
unique_ptr<T, deleter> get()
{
std::unique_lock<std::mutex> ul(objObtainLock);
if (objCont.empty())
throw std::logic_error("no more objects");
auto objPtr = unique_ptr<T, deleter>(objCont.back().release(), [this](T* obj)
{
std::unique_lock<std::mutex> ul(objObtainLock);
objCont.emplace_back(obj);
});
objCont.pop_back();
return objPtr;
}
bool hasMoreObject() const
{
return !objCont.empty();
}
size_t objectsRemained() const
{
return objCont.size();
}
private:
vector<unique_ptr<T>> objCont;
static std::mutex objObtainLock;
};
template<typename T>
std::mutex ObjectPool<T>::objObtainLock;
在使用这个对象池时,我们在需要使用对象池的类中提供一个接口来获取这个类的对象池,并且在初始化时,将指定数量的对象加入对象池中。
最后要说明的是,使用对象池有一个问题即一旦对象池创建了,那只有当程序结束之后,对象池所占用的空间才能够被释放,所以在使用时需要考虑到这一点。