I'm trying to implement a class that's followed in memory by an array of some arbitrary type:
template<class T>
class Buf
{
size_t n;
int refs;
explicit Buf(size_t n) : n(n) { }
// other declarations are here as appropriate
// Followed in memory by:
// T items[n];
};
This would be easy with operator new
:
template<class T>
Buf<T> *make_buf(size_t n)
{
// Assume the caller will take care of constructing the array elements
return new(operator new(sizeof(Buf<T>) + sizeof(T) * n)) Buf<T>(n);
}
template<class T>
void free_buf(Buf<T> *p)
{
// Assume the caller has taken care of destroying the array elements
p->~Buf<T>();
return operator delete(p);
}
template<class T>
T *get_buf_array(Buf<T> *p)
{
return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + sizeof(Buf<T>));
}
But now, how do I implement this using some standard-compliant allocator SomeAllocator
?
Is it guaranteed that SomeAllocator::rebind<char>::other::allocate
will return memory suitably aligned for any type of object? If so, am I otherwise safe to just use an allocator of some char type? If not, do I have any alternatives, or is this task impossible with allocators in general? (In the worst case I suppose I could cast the pointers to uintptr_t
and align them manually, but I'm wondering if there's a better way.)
std::align
... – Jacchar
, since you don't actually have any type that you can allocate for - you just need the raw memory. (It should bestd::allocator_traits<Alloc>::rebind_alloc<char>
, though, andrebind_traits
for the traits... and you need to callallocate
through the traits and obtain a native pointer and all that.) – JacBuf<T>
and realigning the pointer forT
, but I'm not sure if it'd have any advantage or disadvantage. – FiumeBuf<T>
allocates in multiples of that type, so I don't think that would be useful. Sure, you could do some size computations, but at the very least you'd still need to align the address of the first array element somehow. – JacBuf<T>
itself. – FiumeBuf
and the element's alignment is taken care of - otherwise you need to get the max of their alignments. For the allocator... you could thenrebind<Aligned_Allocator<std::alignment_of<Buf<T>>>
whereAlignedAllocator
is specialised so<1>
needs alignment 1 (e.g. contains oneint8_t
),<2>
2 etc.. – Mab