这是我的情况:
有一组Instance
对象,这些对象的数量在运行时确定。
对于每个实例,都会创建一个自定义堆。 (是的,我指的是::HeapCreate()
等所有win32函数)。
struct Instance
{
HANDLE heap;
};
现在,有一些特定于
Instance
的State对象,该对象可以访问(实例)实例。它是1:1的关系。每个实例1个状态。struct State
{
Instance * inst;
};
在那种状态下,我想使用
std::vector
之类的STL容器,但是我希望那些容器使用分配器,该分配器使用实例创建的堆。阅读从C++ 98到C++ 17以及更高版本的
std::allocator
的历史,已经删除了一些旧的要求,但是我的收获是,不可能为我的上面编写这样的分配器显示的用例。假设分配器每次都具有相同的类型,但是是有状态的(例如在使用不同堆HANDLE
的实例中)。所以这是我的问题:
std::pmr
C++ 17命名空间,想知道那里是否有我不熟悉的东西,这将对我的用例有所帮助。 如果您以现代方式(C++ 17和更高版本)展示如何解决此问题的“惯用方式”,您的答案将非常有值(value)。
在这里,我不完整和当前的“正在进行中的工作”。随着时间的推移,我将根据答案和评论以及我自己的进度填写更多内容。
#include <Windows.h>
struct custom_heap_allocator
{
HANDLE heap;
// No default constructor
custom_heap_allocator() = delete;
// an instance is tied to a heap handle.
explicit custom_heap_allocator(HANDLE h)
: heap{ h }
{
}
// can I get away with this....
// copy constructor for same type.
custom_heap_allocator(const custom_heap_allocator& other)
: heap{ other.heap }
{
}
//... or do I need something like this? Or is it somehow covered by rebind?
//template<class U>
//custom_heap_allocator(const custom_heap_allocator<U>& other)
// : heap{ other.heap }
//{
//}
template<class U>
struct rebind {
typedef custom_heap_allocator other;
};
};
template <class T, class U>
constexpr bool operator== (const custom_heap_allocator& a1, const custom_heap_allocator& a2) noexcept
{
return a1.heap == a2.heap;
}
template <class T, class U>
constexpr bool operator!= (const custom_heap_allocator& a1, const custom_heap_allocator& a2) noexcept
{
return a1.heap != a2.heap;
}
注意:关闭
Instance
只会破坏堆(不需要为仍在堆上的东西调用析构函数,因为这些只是简单的数据,而不是系统资源,等等。它们持有的所有动态东西也来自同一堆实例)。
最佳答案
这是您(已编辑)问题中分配器的更完整版本。
在cpp.sh/4viaj上使用std::vector和std::list的一些基本单元测试
template<typename T>
struct custom_heap_allocator
{
using value_type = T;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
// No default constructor
custom_heap_allocator() = delete;
// An instance is tied to a heap handle.
explicit custom_heap_allocator(HANDLE h)
: heap{ h }
{
}
// Instances are copy-constructable and copy-assignable.
custom_heap_allocator(const custom_heap_allocator&) = default;
custom_heap_allocator& operator=(const custom_heap_allocator&) = default;
// All related allocators share the same heap, regardless of type.
template<class U>
custom_heap_allocator(const custom_heap_allocator<U>& other)
: heap{ other.heap }
{
}
// Allocate and deallocate space for objects using the heap.
T* allocate(size_t n) {
return static_cast<T*>(HeapAlloc(heap, 0, sizeof(T) * n));
}
void deallocate(T* ptr, size_t n) {
HeapFree(heap, 0, ptr);
}
// Construct and destroy objects in previously allocated space.
// This *should* be optional and provided by std::allocator_traits,
// but it looks like some std containers don't use the traits.
template< class U, class... Args >
void construct( U* p, Args&&... args ) {
::new((void *)p) U(std::forward<Args>(args)...);
}
template< class U >
void destroy( U* p ) {
p->~U();
}
// Template for related allocators of different types.
template<class U>
struct rebind {
typedef custom_heap_allocator<U> other;
};
private:
// Heap used for all allocations/deallocations.
HANDLE heap;
// Allow all related types to access our private heap.
template<typename> friend struct custom_heap_allocator;
};
关于c++ - C++ 17和更新的std::allocators是否可用于动态数量的自定义堆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59464077/