2017-01-04 7 views
1

続きのstoryテンプレートクラスによる自動メモリプール機能

フラグメンテーションによる動的割り当てが許可されていない安全ソフトウェアを検討してください。動的割り当ては、クラスexplicityがフラグメンテーションを避けるために演算子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) 
     { 
      /* ... */ 
     } 
    } 
}; 

おとぎ話の場合、MemoryPoolを使ったクラスの宣言は甘いでしょう。

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*)))); 

の大きさは、この「不完全型」小胞体を回避することが可能です推測することはできませんror?

解決策を完全に再設計する必要がありますか?

+0

'class Foo'は完全に宣言されていないため不明な' class Interface'から継承しています。 'class Foo'を宣言する前に' class Interface'(メンバーで完全宣言)を宣言しようとしてください – nikniknik2016

+0

@ nikniknik2016これは本当の問題ではありません。私の答えは –

+0

@ nikniknik2016 m.sです。質問の目的のために、コードをあまりにも単純化します。 –

答えて

2

MemoryPoolがインスタンス化されると、Fooはまだ完全な型ではないという問題があります。

clang's error messageはかなり具体的である:

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> 
^

あなたはFooまで、アプリケーションsizeofを遅らせることによってこの問題を回避することができますが、完全な型です。

これは静的メンバ関数を介し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; 
    } 
}; 

live example

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

live example

関連する問題