cosmos icon indicating copy to clipboard operation
cosmos copied to clipboard

ObjectPool逻辑可能有问题

Open vincentbryan opened this issue 6 years ago • 3 comments

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();

vincentbryan avatar Apr 03 '18 12:04 vincentbryan

对象池的使用逻辑或者说流程,应该是(1)对象池初始化,(2)获取对象,(3)回收对象,(4)重复2,3 若干次,(5)对象池销毁或者析构。你所说的第二次删除应该是指(5)。

kikyoo avatar Apr 04 '18 06:04 kikyoo

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

ender233 avatar May 15 '18 04:05 ender233

确实有这个问题,楼上说的对

xiaonaiquan avatar Jan 08 '21 09:01 xiaonaiquan