使 boost::fast_pool_allocator 使用可变参数模板(放置)

Making boost::fast_pool_allocator work with variadic templates (emplace)

本文关键字:参数 放置 fast boost pool allocator 变参      更新时间:2023-10-16

我试图使用boost::fast_pool_allocator作为std::list的分配器,但它找不到使用可变参数模板的construct()的重载。

#include <list>
#include <utility>
#include <boost/pool/pool_alloc.hpp>
int main()
{
typedef std::pair<int, int> Pair;
std::list<Pair, boost::fast_pool_allocator<Pair>> list;
list.emplace(list.begin(), 1, 2);
}

这无法编译,并显示以下错误(缩短):

stl_list.h:514:8: error: no matching function for call to ‘boost::fast_pool_allocator<blah>::construct(std::list<bleh>::_Node*&, int, int)'

查看头文件,似乎boost::fast_pool_allocator只有 C++11 之前的construct()版本(指针和const_reference)。

请注意,将列表定义为std::list<Pair>(即使用默认分配器)工作正常。

有解决方法吗?任何适配器或某种定义分配器特征的方法?我是分配器的新手,所以这对我来说是一个黑暗的土地。

我可以让它工作

list.emplace(list.begin(), Pair(1, 2));

但是 1st) 我在生产中使用的实际类比我用于示例Pair要复杂得多,并且性能至关重要(所以我可以真正使用就地构造),以及 2nd) 理想情况下,我希望有一个直接替代品来替代std::allocator,所以我可以通过一行更改来衡量性能差异。

我正在使用g ++ 4.9.2和boost 1.58.0在Cygwin中进行编译,并且在使用g ++ 4.8.3和boost 1.55.0的linux环境(RHEL5.5)中遇到了同样的问题。

template <typename T,
typename UserAllocator,
typename Mutex,
unsigned NextSize,
unsigned MaxSize >
struct my_pool_allocator:
boost::pool_allocator<T,UserAllocator,Mutex,NextSize,MaxSize>
{
using base=boost::pool_allocator<T,UserAllocator,Mutex,NextSize,MaxSize>;
using base::base;
template <typename U>
struct rebind
{
using other=my_pool_allocator<U, UserAllocator, Mutex, NextSize, MaxSize>;
};
using base::construct;
template<class...Args>
void construct(const typename base::pointer ptr, Args&&...args)
{ new (ptr) T(std::forward<Args>(args)...); }
};

或诸如此类。 从fast_pool_allocator继承,继承其构造函数,编写自定义rebind,继承construct,并添加另一个处理 varargs 的重载construct

我怀疑应该能够编写一个"现代化分配器"模板,该模板可以为您完成大部分工作。

template <class OldAllocator>
struct modernize_allocator:
OldAllocator
{
using base=OldAllocator;
using T=typename base::value_type;
using base::base;
template <typename U>
struct rebind
{
using other=modernize_allocator<typename base::rebind<U>::other>;
};
using base::construct;
template<class...Args>
void construct(const typename base::pointer ptr, Args&&...args)
{ new (ptr) T(std::forward<Args>(args)...); }
};

上面可能有错别字/错误:它只是一个解决方案的草图。

只是为了记录,应该可以直接将fast_pool_allocator与符合 C++11 的容器一起使用,因为容器应该使用allocator_traits::construct,而 只有在调用格式正确的情况下才会调用allocatorconstruct([allocator.traits.members]/p5):

template <class T, class... Args>
static void construct(Alloc& a, T* p, Args&&... args);

效果:如果调用格式正确,则a.construct(p, std::forward<Args>(args)...)调用;否则,调用::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)

问题是libstdc++的std::list仍然不符合C++11标准;它直接在分配器上调用construct。作为一种解决方法,Yakk的答案很好。