【发布时间】:2020-11-04 10:04:40
【问题描述】:
我不知道如何更好地表达我的问题。
我对@987654321@ 的理解是,它会将分配器实例传递给容器,并将其用于构造通过emplace_back 在容器中构造的元素/容器,如果它们需要这样的分配器参数)。
我有以下内容,有点冗长,但这是我能做到的最低限度的说明我正在尝试做的事情:
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <vector>
#include <scoped_allocator>
#include <concepts>
namespace custom_memory
{
class CustomAllocator
{
public:
CustomAllocator(const std::size_t sizeBytes,
void* const start)
:
m_sizeBytes(sizeBytes),
m_usedBytes(0),
m_start(start),
m_current(start)
{
}
void* Allocate(const std::size_t& numBytes,
const std::uintptr_t& alignment)
{
std::size_t space = m_sizeBytes - m_usedBytes;
if(std::align(alignment, numBytes, m_current, space))
{
// the amount used for alignment
m_usedBytes += (m_sizeBytes-m_usedBytes) - space;
// the amount actually needed
m_usedBytes += numBytes;
void* address = m_current;
m_current = reinterpret_cast<void*>(
reinterpret_cast<std::uintptr_t>(m_current) + numBytes);
return address;
}
throw std::bad_alloc();
}
void Free(void* const ptr)
{
// do nothing in this Allocator, but other derived types may
}
void Clear()
{
m_current = m_start;
m_usedBytes = 0;
}
std::size_t GetSize() const { return m_sizeBytes; }
protected:
const std::size_t m_sizeBytes;
std::size_t m_usedBytes;
void* const m_start;
void* m_current;
};
// many types derive from base CustomAllocator type
// allows for my custom allocators to be used in STL containers
template<typename T, typename Alloc>
class STLAdaptor
{
public:
typedef T value_type;
STLAdaptor(Alloc* allocator)
:
m_allocator(allocator)
{
}
[[nodiscard]] constexpr T* allocate(std::size_t n)
{
return reinterpret_cast<T*>
(m_allocator->Allocate(n * sizeof(T), alignof(T)));
}
constexpr void deallocate(T* p, std::size_t n)
{
m_allocator->Free(p);
}
std::size_t MaxAllocationSize() const
{
return m_allocator->GetSize();
}
protected:
Alloc* m_allocator;
};
template<typename T, typename Allocator>
using vector = std::vector<T,
std::scoped_allocator_adaptor<STLAdaptor<T, Allocator>>>;
}
// overloads of global new and delete so I can use them with
// my custom allocators
void* operator new(std::size_t size, custom_memory::CustomAllocator& allocator,
std::uintptr_t alignment)
{
return allocator.Allocate(size, alignment);
}
void operator delete(void* ptr, custom_memory::CustomAllocator& allocator)
{
allocator.Free(ptr);
}
// a type that needs an allocator for it's own internal use
template<typename A>
requires std::derived_from<A, custom_memory::CustomAllocator>
struct Foo
{
A* m_allocator;
int* m_foos;
Foo(A* a)
:
m_allocator(a),
m_foos(new (*a, alignof(int)) int(7))
{
}
Foo(const Foo<A>& other)
:
m_allocator(other.m_allocator),
m_foos(new (*m_allocator, alignof(int)) int(*(other.m_foos)))
{
}
~Foo()
{
operator delete (m_foos, *m_allocator);
}
Foo<A>& operator=(const Foo<A>& rhs)
{
m_allocator = rhs.m_allocator;
*m_foos = *(rhs.m_foos);
return *this;
}
};
int main()
{
const std::size_t memSize = 10000000;
void* mem = std::malloc(memSize);
typedef Foo<custom_memory::CustomAllocator> FooType;
custom_memory::CustomAllocator customAlloc(memSize, mem);
// this works
{
std::vector<FooType, custom_memory::STLAdaptor<FooType,
custom_memory::CustomAllocator>>
vec(&customAlloc);
vec.emplace_back(&customAlloc);
}
// this works
{
custom_memory::vector<FooType,custom_memory::CustomAllocator>
vec(&customAlloc);
vec.emplace_back(&customAlloc); // <-- I don't want to pass this
}
// this doesn't work
{
custom_memory::vector<FooType,custom_memory::CustomAllocator>
vec(&customAlloc);
vec.emplace_back(); // <--- I thought scoped_allocator_adaptor
// would pass the allocator to constructed
// elements?
}
// this also doesn't work
{
typedef std::basic_string<char, std::char_traits<char>,
custom_memory::STLAdaptor<char, custom_memory::CustomAllocator>>
StringType;
custom_memory::vector<StringType,custom_memory::CustomAllocator>
vec(&customAlloc);
vec.emplace_back("string");
}
std::free(mem);
return 0;
}
我有一个 CustomAllocator 派生自一个基(未显示),并且有一堆不同的分配器派生自这个基。
我有一个 STLAdaptor,它允许在 STL 容器中使用 CustomAllocator。这是一个模板类,因为上面提到了许多不同的分配器(我实际上有 STLAdaptor 的特化以及不同的分配器,未显示)。
我尝试将typedef 和std::vector 使用我的STLAdaptor 包裹CustomAllocator 在std::scoped_allocator_adaptor 中。
然后我重载全局 new 和 delete 以接受 CustomAllocator 进行分配。
最后,我有一个需要 CustomAllocator 的类,它在内部使用它为内部类型分配内存(这是我的用例)。
你可以在我的测试中看到我可以:
-
创建一个
std::vector,成功使用我的STLAdaptor包装CustomAllocator。我可以用Foo<CustomerAllocator>类型填充它。 -
我可以使用
std::scoped_allocator_adaptorstd::vector的 typedef。但我需要将CustomAllocator实例显式传递给内部类型 -
我不能省略,但我愿意
-
我也想使用其他 STL 容器
我很确定问题在于std::scoped_allocator_adaptor 有一个STLAdaptor 分配器,而不是CustomAllocator。但是我也无法让它与std::string 一起工作,但我认为这与STLAdaptor 在std::vector 和std::string 之间具有不同类型有关(这是rebind 的来源吗?玩吗?
我正在使用 GCC 10.2.0 和 C++20
任何帮助将不胜感激。
【问题讨论】:
-
这似乎与
memory_resource和polymorphic_allocator非常相似。去那里看看可能不是一个坏主意。 -
谢谢,我也会调查一下
标签: c++ memory-management template-specialization c++20 allocator