Вопрос

I've done a very simple pool allocator for my embedded MCU projects. It's a templated class with a following interface (implementation part is skipped, I can post it too if someone is interested):

template <typename T, size_t size>
class SimplePoolAllocator
{
public:
    SimplePoolAllocator();
    T * allocate();
    void deallocate(T *pointer);
...
}

It works perfectly for "simple" things like classes or PODs, for example:

SimplePoolAllocator<double, 10> poolOfDouble; // returns "double *"
SimplePoolAllocator<WeirdClass, 5> poolOfObjects; // returns "WeirdClass *"

The problem arises if I want to use it for fixed size arrays. This use is of course for raw data buffers - in my project I have two "transfer" types, one has 16 bytes, the other has 100.

So suppose I use sth like that:

SimplePoolAllocator<uint8_t[16], 10> pool1;
SimplePoolAllocator<uint8_t[100], 10> pool2;

Everything seems fine, but the problem is that now allocate() returns sth like that: "uint8_t(*)[16]" and "uint8_t(*)[100]". Ideally I'd like it to return just "uint8_t *" (pointer to beginning) in that case.

I know I can do sth like that:

uint8_t *p = *pool1.allocate(); // additional asterisk to "drop" the array thing from the type

But this looks... weird...

So the question is - how can I improve my SimplePoolAllocator's interface (or anything) to support simple allocation of both "plain" objects (like shown above - classes and PODs) and fixed size arrays, but returning just a pointer to first element? Can it be done without using std::array and using it's data() member funcion, or without additional '*' all around the place? C++11 features are OK with me, if there would be sth that would "convert" the types like this it could save me here: WeirdClass -> WeirdClass *, uint8_t[16] -> uint8_t *. I cannot easily wrap the buffers in classes, because I handle the transfers in interrupt in "raw" form - all I need in there is the pointer to buffer, which is later passed via message queue to task for processing, with "type" (size) as one of elements of the message. I would like to avoid using virtual functions for this simple task if possible (;

Can it be done at all, or maybe I'm asking too much? Maybe the only solution is to make the interface to the template sth like this:

template <typename T, size_t array_size, size_t size>

so I'd have:

SimplePoolAllocator<WeirdClass, 1, 10> pool1;
SimplePoolAllocator<uint8_t, 16, 10> pool2;

but this also does not look very good...

Thx in advance for any suggestions! Please note that this questions is about a project for microcontroller, so using Boost or sth like that is out of the question.

Это было полезно?

Решение

You should specialize your class:

template <typename T, size_t size>
class SimplePoolAllocator
{
public:
    SimplePoolAllocator();
    T * allocate();
    void deallocate(T *pointer);
...
};

template <typename T, size_t N, size_t size>
class SimplePoolAllocator<T[N],size> // <-- here
{
public:
    SimplePoolAllocator();

    // you can now use different signatures and different implementations:
    T ** allocate();
    void deallocate(T **pointer);
...
};

This is probably the easiest way to separate those cases and treat them independently.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top