cosmos
cosmos copied to clipboard
ObjectPool逻辑可能有问题
ObjectPool的Init中:
auto constructName = typeid(Constructor<Args...>).name(); //不区分引用
for (size_t i = 0; i <num; i++){
m_object_map.emplace(constructName, shared_ptr<T>(new T(std::forward<Args>(args)...), [this, constructName](T* p) //删除器中不直接删除对象,而是回收到对象池中,以供下次使用
{
m_object_map.emplace(std::move(constructName), std::shared_ptr<T>(p));
}));
}
当对象第一次被回收之后重新加入map时没有再次添加删除器,那么第二次删除之后就没有了。但第三次再次获取时就会获得空指针,如:
ObjectPool<Test> objectPool;
objectPool.Init(2, 3, 4.5);
{
{
auto t1 = objectPool.Get<int, double>(); t1->print();
auto t2 = objectPool.Get<int, double>(); t2->print();
}
auto t1 = objectPool.Get<int, double>(); t1->print();
auto t2 = objectPool.Get<int, double>(); t2->print();
}
auto t1 = objectPool.Get<int, double>(); t1->print();
auto t2 = objectPool.Get<int, double>(); t2->print();
对象池的使用逻辑或者说流程,应该是(1)对象池初始化,(2)获取对象,(3)回收对象,(4)重复2,3 若干次,(5)对象池销毁或者析构。你所说的第二次删除应该是指(5)。
@kikyoo 我理解他说的是 (2),再次获取对象的情况。而这种情况下 原代码中确实是没有删除器的。
template<typename... Args>
std::shared_ptr<T> Get()
{
string constructName = typeid(Constructor<Args...>).name();
auto range = m_object_map.equal_range(constructName);
for (auto it = range.first; it != range.second; ++it)
{
auto ptr = it->second;
m_object_map.erase(it);
return ptr;
}
获取对象的时候在池中删除,并没有给新的删除器. 所以在第二次取出来的时候已经是个普通的std::shared_ptr<T>
,析构后也无法放入池中。
想对照的看SimpleObjectPool.hpp的处理:
每次把对象从池中拿出来,立马注册了一个DeleterType
,保证析构后可以放到池子中。
std::unique_ptr<T, DeleterType> get()
{
if (pool_.empty())
{
throw std::logic_error("no more object");
}
//every time add custom deleter for default unique_ptr
std::unique_ptr<T, DeleterType> ptr(pool_.back().release(), [this](T* t)
{
pool_.push_back(std::unique_ptr<T>(t));
});
pool_.pop_back();
return std::move(ptr);
}
确实有这个问题,楼上说的对