是否可以创建shared_ptr的对象池? 在我脑海中勾勒出这一点,我可以看到两种方法,但每种方法都有一个缺陷:
如果T对象存储在可重用的池中,那么在get()请求中将T包装在shared_ptr中的行为将导致每次在堆上重新分配控制块 - 因此打破了概念对象池。
如果shared_ptr对象存储在可重用池中,则shared_ptr对象必须停止存在以启动自定义删除器,并且仅使用T指针调用自定义删除器函数。所以没有什么可以回收的。
答案 0 :(得分:2)
经过详尽的研究和测试后,我得出结论认为,有一个 no 合法的方式(从C ++ 11或更低版本开始)来创建一个可重用的shared_ptr<T>
&#39;直接当然,人们可以很容易地创建一个T
个对象池,这些对象可以为shared_ptr<T>
提供服务,但这会导致与控制块的每个服务进行堆分配。
shared_ptr<T>
的对象池(这是我发现的唯一方式它)。通过间接,我的意思是必须实现一个自定义的内存池&#39;样式分配器,用于存储以便在shared_ptr<T>
控制块被销毁时释放的内存。然后将此分配器用作`shared_ptr&#39;的第三个参数。构造:
template< class Y, class Deleter, class Alloc >
std::shared_ptr( Y* ptr, Deleter d, Alloc alloc );
shared_ptr<T>
仍然会被堆内存构造/分配和删除/解除分配 - 没有办法阻止它 - 但是通过自定义分配器使内存可以重用,确定性的内存占用可以是实现。
答案 1 :(得分:0)
是的,这是可能的。但是,我会考虑让它返回boost::intrusive_ptr<T>
,而不是让您的池返回std::shared_ptr<T>
。您可以intrusive_ptr_release()
负责从池中释放该块,然后由您的用户构建T
以便您可以创建intrusive_ptr<T>
。
答案 2 :(得分:0)
您可以将对象存储在池中(例如,作为unique_ptr)。该池根据请求返回shared_ptr。定制删除器将数据返回到池中。一个简单的例子如下:
#ifndef __POOL_H_
#define __POOL_H_
#include <list>
#include <mutex>
#include <algorithm>
#include <memory>
#include <stdexcept>
namespace common {
template<class T, bool grow_on_demand=true>
class Pool
{
public:
Pool(const char* name_p, size_t n)
: mutex_m(), free_m(0), used_m(0), name_m(name_p)
{
for (size_t i=0; i<n; i++)
{
free_m.push_front( std::make_unique<T>() );
}
}
const char* getName() const
{
return name_m.c_str();
}
std::shared_ptr<T> alloc()
{
std::unique_lock<std::mutex> lock(mutex_m);
if (free_m.empty() )
{
if constexpr (grow_on_demand)
{
free_m.push_front( std::make_unique<T>() );
}
else
{
throw std::bad_alloc();
}
}
auto it = free_m.begin();
std::shared_ptr<T> sptr( it->get(), [=](T* ptr){ this->free(ptr); } );
used_m.push_front(std::move(*it));
free_m.erase(it);
return sptr;
}
size_t getFreeCount()
{
std::unique_lock<std::mutex> lock(mutex_m);
return free_m.size();
}
private:
void free(T *obj)
{
std::unique_lock<std::mutex> lock(mutex_m);
auto it = std::find_if(used_m.begin(), used_m.end(), [&](std::unique_ptr<T> &p){ return p.get()==obj; } );
if (it != used_m.end())
{
free_m.push_back(std::move(*it));
used_m.erase(it);
}
else
{
throw std::runtime_error("unexpected: unknown object freed.");
}
}
std::mutex mutex_m;
std::list<std::unique_ptr<T>> free_m;
std::list<std::unique_ptr<T>> used_m;
std::string name_m;
};
}
#endif /* __POOL_H_ */
默认情况下,如果您从空池中分配新对象(grow_on_demand = true),则池会添加新项目。
n
元素并将其添加到池中(使用默认构造函数)。mypool.alloc()
,您可以从池中获取对象。[=](T* ptr){ this->free(ptr); }
内部通过alloc()
隐式发生。)