在具有预分配块的自定义STL分配器中重新绑定

Mr.*_*C64 16 c++ memory-management stl allocator c++11

我将构建一个自定义分配器,预分配一个大块(数组)来存储N某些类的元素T,然后只需增加数组内的索引来为服务分配请求.

因为我希望对预分配块中的元素进行任何初始化,所以这样的东西不起作用:

T buffer[N];
Run Code Online (Sandbox Code Playgroud)

因为在这种情况下,T将为N块的元素调用构造函数.

既然我的理解是std::aligned_storage不调用T构造函数,我想使用std::aligned_storage,像这样:

std::aligned_storage<
    N * sizeof(T),
    std::alignment_of<T>::value 
>::type buffer;

T* base = static_cast<T*>( static_cast<void*>(&buffer) );
Run Code Online (Sandbox Code Playgroud)

然后,当请求T的分配(直到(base+N))时,分配器可以仅增加基指针,并且在需要时可以在适当的位置构建T (具有放置new).

我想使用此方案为STL容器定义自定义分配器.但是,在我看来,重新绑定可能存在问题.事实上,如果我的理解是正确的,一个STL分配器应支持从类型重新绑定T到一个类型U,例如,因为喜欢的容器std::list<T>(或其它基于节点的容器一样std::map)使用allocator分配的节点上,但不是类型T,但不同type U(包含T节点的"header"开头信息).那么,上述std::aligned_storage方法是否适用于重新绑定?或者(我认为)Ts 的正确对齐并不意味着另一种不同类型的正确对齐U

怎么可以解决这个问题?

我怎样才能定义上述内容buffer以使其适用于重新绑定到某种不同类型U

这个问题应该从不同的角度受到攻击吗?如果是这样,什么?

How*_*ant 11

你走在正确的轨道上.

一个令人恼火的细节是,分配器的副本必须比较相等,甚至转换(反弹)副本.比较相等意味着他们可以释放彼此的指针.所以容器中,如std::list<int>将重新绑定your_alloc<int>your_alloc<node<int>>,然后构建一个your_alloc<node<int>>使用your_alloc<int>.从技术上讲,你your_alloc<node<int>>必须解除分配的指针your_alloc<int>.

是我尝试满足这一要求.随意复制/修改/滥用此代码.我的目的是教育,而不是成为世界的分配器供应商(无论如何都不会有利可图:-)).

这个例子采用了略微不同的对齐方法:我碰巧知道在我感兴趣的平台(OS X,iOS)上malloc返回16字节对齐的内存,所以我的所有自定义分配器都需要返回.您可以将该数字更改为适合您系统的数字.

对准这硬连线意味着单个池可以安全地提供一些allocator<int>allocator<node<int>>,因为他们是排列所有的16个字节(这就是足够了).并且它还意味着副本,甚至是转换后的副本,可以检测指针何时指向缓冲区,因为副本都共享相同的缓冲区.

换句话说,C++委员会已经有效地指定了分配器是引用类型:副本是等效的并且指向相同的内存池.

您可以使用实际嵌入到分配器中的内存池来避免作弊,但在某些实现中只能使用某些容器,并且您无法使用标准中的引用来备份.