是否可以使用自定义分配器来分配任意大小的区域?
Is it possible to use a custom allocator to allocate an arbitrary sized area?
我有一个容器 class 管理不同块中的底层内存。块的数量随容器中存储的对象数量而变化。每当容器即将超过当前可用内存时,我都会分配一块新的内存。而且,只要不再使用,就释放一个块。因此,数字块在运行时是可变的。因此,我必须将块指针存储在动态 growing/shrinking 数组中。
/*** Container Class ***/
template<class T, class Allocator = std::allocator<T>>
class CustomContainer{
public:
// Some member methods here..
private:
void createNewChunk()
{
// Some code goes here ...
newChunkAddr = new T*[CHUNK_SIZE];
}
void destroyChunk(T* chunkAddr)
{
// Some code goes here ...
delete [] chunkAddr;
}
private:
/*** Members ***/
// Some other members ...
std::size_t size = 0;
T** chunks = nullptr;
Allocator allocator;
};
只要使用此容器的系统有堆,一切都很好,因此可以正确实现 operator new
。当系统不使用 operator new
并且用户假定容器将使用它提供的 Allocator
分配任何动态资源时会出现问题。
经过快速的头脑风暴,我立即想到可以使用 std::allocator_traits
class 的 allocate
method 来分配所需的 space。不幸的是,该方法只能分配大小恰好是分配器中使用的模板值类型倍数的区域。下面是对应函数的解释:
Uses the allocator a to allocate n*sizeof(Alloc::value_type)
bytes of
uninitialized storage. An array of type Alloc::value_type[n]
is
created in the storage, but none of its elements are constructed.
问题来了,allocating/deallocating space 存储块指针的正确方法是什么?
what is the proper way of allocating/deallocating the space for storing the chunk pointers?
任何分配内存的正确方法都是正确的方法。每个都有其优点和缺点。您应该根据哪些优点和缺点对您的用例很重要来进行选择。
如果您希望避免动态存储,您可以使用静态存储,但这会限制您的最大块数。或者如果你不介意动态存储,那么你可以使用全局分配器。
您甚至可以通过提供单独的自定义分配器让用户自定义该分配。
标准容器的方式——这也是一种正确的方式,但不是唯一正确的方式——是它们会创建一个类型为 std::allocator_traits<Allocator>::rebind_alloc<T*>
的新分配器。如果您确实采用了使用单独的自定义分配器的方式,那么这将是第二个分配器的合理默认值。
I've to store the chunk pointers in a dynamically growing/shrinking array.
标准库中有一个用于该目的的容器:std::vector
。您可以在您的容器中使用它。
P.S。您对容器的描述与 std::deque
非常相似。考虑使用它是否会更简单。
我有一个容器 class 管理不同块中的底层内存。块的数量随容器中存储的对象数量而变化。每当容器即将超过当前可用内存时,我都会分配一块新的内存。而且,只要不再使用,就释放一个块。因此,数字块在运行时是可变的。因此,我必须将块指针存储在动态 growing/shrinking 数组中。
/*** Container Class ***/
template<class T, class Allocator = std::allocator<T>>
class CustomContainer{
public:
// Some member methods here..
private:
void createNewChunk()
{
// Some code goes here ...
newChunkAddr = new T*[CHUNK_SIZE];
}
void destroyChunk(T* chunkAddr)
{
// Some code goes here ...
delete [] chunkAddr;
}
private:
/*** Members ***/
// Some other members ...
std::size_t size = 0;
T** chunks = nullptr;
Allocator allocator;
};
只要使用此容器的系统有堆,一切都很好,因此可以正确实现 operator new
。当系统不使用 operator new
并且用户假定容器将使用它提供的 Allocator
分配任何动态资源时会出现问题。
经过快速的头脑风暴,我立即想到可以使用 std::allocator_traits
class 的 allocate
method 来分配所需的 space。不幸的是,该方法只能分配大小恰好是分配器中使用的模板值类型倍数的区域。下面是对应函数的解释:
Uses the allocator a to allocate
n*sizeof(Alloc::value_type)
bytes of uninitialized storage. An array of typeAlloc::value_type[n]
is created in the storage, but none of its elements are constructed.
问题来了,allocating/deallocating space 存储块指针的正确方法是什么?
what is the proper way of allocating/deallocating the space for storing the chunk pointers?
任何分配内存的正确方法都是正确的方法。每个都有其优点和缺点。您应该根据哪些优点和缺点对您的用例很重要来进行选择。
如果您希望避免动态存储,您可以使用静态存储,但这会限制您的最大块数。或者如果你不介意动态存储,那么你可以使用全局分配器。
您甚至可以通过提供单独的自定义分配器让用户自定义该分配。
标准容器的方式——这也是一种正确的方式,但不是唯一正确的方式——是它们会创建一个类型为 std::allocator_traits<Allocator>::rebind_alloc<T*>
的新分配器。如果您确实采用了使用单独的自定义分配器的方式,那么这将是第二个分配器的合理默认值。
I've to store the chunk pointers in a dynamically growing/shrinking array.
标准库中有一个用于该目的的容器:std::vector
。您可以在您的容器中使用它。
P.S。您对容器的描述与 std::deque
非常相似。考虑使用它是否会更简单。