std::unique_ptr<T[]> 和自定义分配器删除器

std::unique_ptr<T[]> and custom allocator deleter

我正在尝试将 std::unique_ptr<T[]> 与自定义内存分配器一起使用。基本上,我有自定义分配器,它们是 IAllocator 的子类,它提供以下方法:

void* Alloc( size_t size )
template<typename T> T* AllocArray( size_t count )
void Free( void* mem )
template<typename T> void FreeArray( T* arr, size_t count )

由于底层内存可能来自预先分配的块,我需要特殊的 ...Array() 方法来分配和释放数组,它们 allocate/free 内存并调用 T() / ~T() 在范围内的每个元素上。 现在,据我所知,std::unique_ptr 的自定义删除器使用签名:

void operator()(T* ptr) const

unique_ptr<T[]> 的情况下,通常你会调用 delete[] 并完成它,但我必须调用 FreeArray<T>,为此我需要元素的数量范围。只给出原始指针,我认为没有办法获得范围的大小,因此我唯一能想到的是:

std::unique_ptr<T[], MyArrDeleter> somePtr( allocator.AllocArray<T>( 20 ), MyArrDeleter( allocator, 20 ) );

基本上数组的大小必须手动传递到删除器对象中。有一个更好的方法吗?这对我来说似乎很容易出错...

T* 不包含此类信息,unique_ptr 也不知道数组的大小(因为它直接使用 delete [] 正如您所说)。您可以让 T 成为 unique_ptr<T> 来自动管理销毁,但是如果整个连续的 T* 由内存分配器管理(而不是单个 T* 对象)。例如:

unique_ptr<unique_ptr<Foo>[]> data;
data.reset(new unique_ptr<Foo>[50]);
data[0].reset(new Foo());

是的,肯定有更好的方法:
使用制造商功能。

template<class T, class A> std::unique_ptr<T[], MyArrDeleter>
my_maker(size_t count, A&& allocator) {
    return {somePtr(allocator.AllocArray<T>(count), MyArrDeleter(allocator, count)};
}

auto p = my_maker<T>(42, allocator);