按模板类划分的自动内存池功能

Automatic memory pool feature by template class

本文关键字:内存 功能 划分      更新时间:2023-10-16

故事的延续。

考虑安全软件,其中不允许使用碎片进行动态分配。仅当类显式定义运算符newdelete以避免碎片时,才允许动态分配。

现在,我们有机会为我们想要获得的任何类优化运算符newdelete的显式定义。乍一看,任何类都可以从中继承的模板类是最终用户使用的最简单、最清晰的方法。

template<class T, unsigned size>
class MemoryPool
{
private:
    struct Pool
    {
        bool    allocated         __attribute__ ((aligned (sizeof(void*))));
        uint8_t memory[sizeof(T)] __attribute__ ((aligned (sizeof(void*))));
    };
    static std::array<uint8_t[sizeof(Pool)], size> memoryPool;
public:
    void* operator new(std::size_t) noexcept
    {
        T* ret = nullptr;
        for(auto it = memoryPool.begin(); it != memoryPool.end(); ++it)
        {
           /* ... */
        } 
        return ret;
    }
    void operator delete(void* ptr) noexcept
    {
        for(auto it = memoryPool.begin(); it != memoryPool.end(); ++it)
        {
            /* ... */
        }
    }
};

如果这是一个童话故事,用记忆池宣布上课会很甜蜜。

class Interface
{/*...*/};
class Foo : public Interface,  MemoryPool<Foo, 8>
{/*...*/};
class Bar : public Interface
{/*...*/};

和对象的声明:

Foo* foo = new Foo(); // goes to dedicated memory pool
Bar* bar = new Bar(); // fails on build

但即使static std::array<uint8_t[sizeof(Pool)], size> memoryPool;是静态的并且会去类之外,所以它不会改变类的大小,编译器也会抱怨Foo不完整,无法推断出Foo的大小

src/metal/dynamic.hpp:14:24: error: invalid application of 'sizeof' to incomplete type 'Foo'
   uint8_t memory[sizeof(T)] __attribute__ ((aligned (sizeof(void*))));

是否可以解决此"不完整类型"错误?

还是我应该完全重新设计解决方案?

问题是Foo在实例化MemoryPool时还不是完整的类型。

Clang 的错误消息非常具体:

main.cpp:10:24: error: invalid application of 'sizeof' to an incomplete type 'Foo'
        uint8_t memory[sizeof(T)] __attribute__ ((aligned (sizeof(void*))));
                       ^~~~~~~~~
main.cpp:13:31: note: in instantiation of member class 'MemoryPool<Foo, 8>::Pool' requested here
    static std::array<uint8_t[sizeof(Pool)], size> memoryPool;
                              ^
main.cpp:35:20: note: in instantiation of template class 'MemoryPool<Foo, 8>' requested here
class Foo : public MemoryPool<Foo, 8>
                   ^
main.cpp:35:7: note: definition of 'Foo' is not complete until the closing '}'
class Foo : public MemoryPool<Foo, 8>
  ^

您可以通过将应用程序sizeof延迟到Foo是完整的类型来解决此问题。

这可以通过在静态成员函数访问memoryPool来完成:

template<class T, unsigned size>
class MemoryPool
{
private:
    struct Pool
    {
        bool    allocated         __attribute__ ((aligned (sizeof(void*))));
        uint8_t memory[sizeof(T)] __attribute__ ((aligned (sizeof(void*))));
    };
    template <typename P>
    static std::array<uint8_t[sizeof(P)], size>& getPool()
    {
        static std::array<uint8_t[sizeof(P)], size> memoryPool;
        return memoryPool;
    }
public:
    void* operator new(std::size_t) noexcept
    {
        T* ret = nullptr;
        for(auto it = getPool<Pool>().begin(); it != getPool<Pool>().end(); ++it)
        {
           /* ... */
        } 
        return ret;
    }
};

现场示例

C++14 允许稍微简单的实现:

template<class T, unsigned size>
class MemoryPool
{
private:
    struct Pool
    {
        bool    allocated         __attribute__ ((aligned (sizeof(void*))));
        uint8_t memory[sizeof(T)] __attribute__ ((aligned (sizeof(void*))));
    };
    static auto& getPool()
    {
        static std::array<uint8_t[sizeof(Pool)], size> memoryPool;
        return memoryPool;
    }
public:
    void* operator new(std::size_t) noexcept
    {
        T* ret = nullptr;
        for(auto it = getPool().begin(); it != getPool().end(); ++it)
        {
           /* ... */
        } 
        return ret;
    }
};

现场示例