C++ 如何在自定义池分配器中使用std::vector时消除无用的分配和构造?

C++ 如何在自定义池分配器中使用std::vector时消除无用的分配和构造?,c++,memory,vector,allocator,C++,Memory,Vector,Allocator,我有一个自定义池分配器,我希望它与std::vector一起使用 #包括 #包括 #包括 #包括 模板 结构对象池 { 使用值_type=T; 使用指针=值_类型*; 对象池() { 用于(自动i=1;i

我有一个自定义池分配器,我希望它与std::vector一起使用

#包括
#包括
#包括
#包括
模板
结构对象池
{
使用值_type=T;
使用指针=值_类型*;
对象池()
{
用于(自动i=1;iallocator(2)
时,您需要返回一个指向至少
2*sizeof(T)的块的指针
块。分配器仅返回指向单个块的指针。当向量构造函数将第2(或第3)个元素添加到新生成的向量时,它将覆盖尚未专门分配的内存。下次调用分配器将分配该内存,从而导致向量损坏

向量的分配内存是连续的。当您第一次调用
push_back
时,将为向量分配一个元素(其容量为1)。这将生成输出的第1-2行

在第二次调用
push_back
时,由于向量的容量已满,将请求一个新块。这将生成输出的第2-7行。第4行将现有元素复制到新内存块,第5行构造刚刚添加的新元素,第6行从原始内存b中销毁该元素第7行是原始内存块被释放(返回给分配器)时,向量的容量为2

下一次调用
push_back
将再次导致向量的大小调整,生成输出的第8-14行。第9-10行将现有元素复制到新内存块,第11行构造新添加的元素,第12-13行在旧内存块中销毁它们,第14行将旧内存块返回给分配器

以下行上的输出已损坏,因为稍后对分配器的调用返回指向向量对象正在使用的内存的指针。由此产生的数据复制会移动不正确或损坏的数据

解决方案是让
allocate
函数保留适当数量的块。(因此
allocate(2)
应该向前推进
nextFreeItem
两个块,假设向前推进的两个块是连续的。)

传递给的值是将连续存储在内存中的对象数。这意味着当调用
分配器(2)
时,您需要返回一个指向至少包含
2*sizeof(T)
块的块的指针。您的分配器只返回一个指向单个块的指针。当向量构造函数添加第二个(或第三个)元素添加到新生成的向量,它将覆盖尚未专门分配的内存。下一次调用
allocator
将分配该内存,从而导致向量损坏

向量的分配内存是连续的。当您第一次调用
push_back
时,将为向量分配一个元素(其容量为1)。这将生成输出的第1-2行

在第二次调用
push_back
时,由于向量的容量已满,将请求一个新块。这将生成输出的第2-7行。第4行将现有元素复制到新内存块,第5行构造刚刚添加的新元素,第6行从原始内存b中销毁该元素第7行是原始内存块被释放(返回给分配器)时,向量的容量为2

下一次调用
push_back
将再次导致向量的大小调整,生成输出的第8-14行。第9-10行将现有元素复制到新内存块,第11行构造新添加的元素,第12-13行在旧内存块中销毁它们,第14行将旧内存块返回给分配器

以下行上的输出已损坏,因为稍后对分配器的调用返回指向向量对象正在使用的内存的指针。由此产生的数据复制会移动不正确或损坏的数据


解决方案是让
allocate
函数保留适当数量的块。(因此
allocate(2)
应该向前推进
nextFreeItem
两个块,假设向前推进的两个块是连续的。)

分配器决定分配应如何进行,而不是何时进行。后者完全由使用分配器的容器控制。分配器决定分配应如何进行,而不是何时进行。后者完全由使用分配器的容器控制。
ObjectPool: allocate whatever // this is space for 5
ObjectPool: construct         // constructs 5
ObjectPool: allocate whatever // this is space for 3
ObjectPool: construct         // constructs 3
ObjectPool: allocate whatever // this is space for 523
ObjectPool: construct         // constructs 523, but actual output gives garbage value
ObjectPool: destroy           // destroys 523
ObjectPool: deallocate        // deallocates 523
ObjectPool: destroy           // destroys 3
ObjectPool: destroy           // destroys 5
ObjectPool: deallocate        // deallocates 3 and 5