Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use STL-compliant allocators for heterogeneous memory allocations

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.)

like image 258
user541686 Avatar asked Aug 04 '14 00:08

user541686


1 Answers

I was thinking the solution could be by creating a notional early array.

+-----------+
|Buf<T>     |
+-------+---+---+-------+-------+
|T[0]   | T[1]  |T[2]   |  T[3]...
+-------+-------+-------+-------+

With the non-overlapping T[2], T[3], ... being the required array of T.

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];
};

The number of ruined elements would be :-

const size_t lead = ( sizeof(Buf<T>) + sizeof(T) - 1) / sizeof(T);

Finally the raw memory of i can be accessed by

(reinterpret_cast<T*>( this ) )[ i + lead ];
like image 65
mksteve Avatar answered Oct 22 '22 23:10

mksteve