【问题标题】:Pool allocator for fixed-size arrays in C++C++ 中固定大小数组的池分配器
【发布时间】:2013-10-28 19:44:08
【问题描述】:

我为我的嵌入式 MCU 项目做了一个非常简单的池分配器。这是一个模板类,有如下接口(实现部分略过,有兴趣的我也可以贴出来):

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

它非常适用于类或 POD 等“简单”事物,例如:

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

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

所以假设我是这样使用的:

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

一切似乎都很好,但问题是现在 allocate() 会返回这样的结果:“uint8_t(*)[16]”和“uint8_t(*)[100]”。理想情况下,我希望它只返回“uint8_t *”(指向开始的指针)。

我知道我可以这样做:

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

但这看起来……很奇怪……

所以问题是 - 我如何改进 SimplePoolAllocator 的接口(或任何东西)以支持“普通”对象(如上所示 - 类和 POD)和固定大小数组的简单分配,但只返回指向 first 的指针元素?可以在不使用 std::array 和使用它的 data() 成员函数的情况下完成,或者在整个地方都没有额外的 '*' 吗? C ++ 11 功能对我来说没问题,如果有某种东西可以“转换”这样的类型,它可以在这里救我:WeirdClass -> WeirdClass *,uint8_t[16] -> uint8_t *。我不能轻易地将缓冲区包装在类中,因为我以“原始”形式处理中断中的传输 - 我需要的只是指向缓冲区的指针,该指针稍后通过消息队列传递给任务进行处理,带有“类型”( size) 作为消息的元素之一。如果可能的话,我想避免在这个简单的任务中使用虚函数(;

可以做到吗,还是我要求太多了?也许唯一的解决方案是让模板的接口像这样:

template <typename T, size_t array_size, size_t size>

所以我有:

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

但这看起来也不是很好......

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

【问题讨论】:

    标签: c++ arrays templates c++11 allocation


    【解决方案1】:

    你应该专攻你的课程:

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

    这可能是分离这些案例并独立处理它们的最简单方法。

    【讨论】:

    • 好的,好主意!我猜“**”是错误的(我的编译器抱怨(;),但是有没有办法我可以将这种专门的 allocate()“重定向”到第一类的“通用”分配?如果我只是做“T * allocate() { return SimplePoolAllocator::allocate(); };" 它显然会创建无休止的递归......换句话说 - 有没有一种简单的方法可以只编写一次分配器的代码?也许我应该将第一个类专门化为第二个类的特例,N == 1?
    • @FreddieChopin T** 并不是一个真正的建议你应该做什么,它只是作为一个占位符来表明它可以不同于基本情况。选择你想要和需要的任何东西。对于通用代码,创建一个基类并将其放入其中,从中派生上述两个类。使用类型/类系统对您有利。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 2011-12-04
    • 2014-11-15
    • 2013-01-05
    • 2012-03-17
    • 2018-02-27
    • 2020-08-12
    相关资源
    最近更新 更多