在c++中为固定大小的数组分配分配器

时间:2022-11-05 21:45:32

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

我为我的嵌入式MCU项目做了一个非常简单的池分配器。它是一个模板类,具有以下接口(实现部分被跳过,如果有人感兴趣,我也可以发布它):

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.

如果我想将它用于固定大小的数组,就会出现问题。这种用法当然用于原始数据缓冲区——在我的项目中,我有两个“传输”类型,一个有16个字节,另一个有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.

一切看起来都很好,但是问题是现在分配()返回如下内容:“uint8_t(*)[16]”和“uint8_t(*)[100]”。理想情况下,我希望它只返回“uint8_t *”(指向开始)。

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 (;

因此,问题是——如何改进SimplePoolAllocator的接口(或其他任何东西),以支持简单地分配“普通”对象(如上面所示)和固定大小的数组,但只返回一个指向第一个元素的指针?是否可以不使用std::array并使用它的data()成员funcion,或者不使用其他“*”?c++ 11的特性对我来说没有问题,如果有什么东西可以“转换”这类类型的话,它可以在这里拯救我:怪物类->怪物类*,uint8_t[16] -> uint8_t *。我不能轻易地将缓冲区封装到类中,因为我以“原始”的形式处理中断中的传输——我在其中所需要的只是一个指向缓冲区的指针,该指针随后通过消息队列传递给任务进行处理,“type”(size)是消息的元素之一。如果可能的话,我希望避免在这个简单的任务中使用虚拟函数(;

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.

谢谢您的建议!请注意,这个问题是关于一个微控制器的项目,所以使用Boost或类似的东西是不可能的。

1 个解决方案

#1


4  

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.

这可能是分离这些病例并独立治疗的最简单的方法。

#1


4  

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.

这可能是分离这些病例并独立治疗的最简单的方法。