オブジェクトプールやヒープ内のオブジェクトを簡単に作成

私はC ++で別の自転車自身のアセンブリを共有したいです。 自転車はすぐに作成したオブジェクトを生成することができます。 結果は、発生率である(戻らない)30%速い新しいよりもオブジェクト。 オブジェクトプールは - 新しいものではない、と一般的には - 何それについて何かを言います。 しかし、彼らが言うように - 詳細主なもの。



それが起こったとして、それは、C ++でのプロジェクトで私の小さなオブジェクトの膨大な量を取りました。 ときに、彼らが必要なもの、それはヒープで、判明したとして。 オブジェクトは、空間内の位置の説明以外の何物でもなかったです。 そして、double型、およびいくつかの補助変数の4x4のマトリックスを含みます。 初期形式を単純化したため、クラス(この場合は構造)が次の形式を持っていると仮定します。



struct Position{ double m[16]; int s; }
      
      





132のバイトについて - それはあります。

それらの間でのオブジェクトの作成はちょうど新しい介していたいくつかの方法を試してみました、それはオブジェクトプールを使用してこれを行うことが最善であるものになりました。 額に直接新しいのは、リソースを集中的に使用する操作です。



すぐにboostを使用して予約します。 だから、おそらく私はここで自転車を記述する。 それにもかかわらず、私は個人的にそのようなことを見つけませんでした(おそらく、私はそれを正しく呼び出す方法を知らなかったという事実から)が、非常に迅速に動作することが判明しました。



オブジェクトプールは非常によく知られており、一般に、実装する単純なパターンです。 これは複雑に思えます-オブジェクトのスタックを作成し、必要に応じて与えます。 すべて配った場合 - より作成。 オブジェクトが不要になった場合、それを削除するのではなく、空きオブジェクトのスタックに戻します。 ここではクラスが実装このパターンの例は以下のとおりです。



 template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: std::vector<T> buffer; std::vector<T*> free_ptrs; //   ( ,  chunk_size = 1 ).  chunk_size = 1   loop. void makeMore(){ //   vector.reserve() ,     reserve     //  vector.size() ,     .   //    STL. for (int i = 0; i < chunk_size ; ++i) { buffer.emplace_back(); //         ! free_ptrs.emplace_back(&buffer.back()); //     } } }
      
      



= template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: std::vector<T> buffer; std::vector<T*> free_ptrs; // ( , chunk_size = 1 ). chunk_size = 1 loop. void makeMore(){ // vector.reserve() , reserve // vector.size() , . // STL. for (int i = 0; i < chunk_size ; ++i) { buffer.emplace_back(); // ! free_ptrs.emplace_back(&buffer.back()); // } } }



{ template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: std::vector<T> buffer; std::vector<T*> free_ptrs; // ( , chunk_size = 1 ). chunk_size = 1 loop. void makeMore(){ // vector.reserve() , reserve // vector.size() , . // STL. for (int i = 0; i < chunk_size ; ++i) { buffer.emplace_back(); // ! free_ptrs.emplace_back(&buffer.back()); // } } }



{ template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: std::vector<T> buffer; std::vector<T*> free_ptrs; // ( , chunk_size = 1 ). chunk_size = 1 loop. void makeMore(){ // vector.reserve() , reserve // vector.size() , . // STL. for (int i = 0; i < chunk_size ; ++i) { buffer.emplace_back(); // ! free_ptrs.emplace_back(&buffer.back()); // } } }







アプリケーション:

 Factory<Position> pool; pool.get();
      
      





方法以下のような欠点を考慮してください。

- 実際には、(10,000 - 1,000,000)の膨大な数の作成、ヒープ上の小さなオブジェクトのは、パフォーマンスの大幅な地盤沈下を引き起こしました。 もちろん、中に、このような躊躇は、ときにのみ、元の初期化が行われます。 しかし、まだ。 あなたがよく行うことができるなら、なぜそれをしませんか?

- 私たちは、デフォルトコンストラクタであるべきオブジェクトのクラスを作成しました!

-オブジェクトは未定義の状態で戻ります。 あなたは確かに、コンストラクタ/初期化子の呼び出しを追加、より多くのその上で、以下のことができます。



オブジェクトがネイティブ配列でスマートに作成されていることがわかりました:

 T* array = new T[];
      
      





そして、これによると、私たちは同様の方法で作成し、ストアオブジェクトしてみてください。

STL'nyのbuffer.reserveを作るのに十分だったと思われます。 しかし、配列が増えるたびに、新しいネイティブ配列が作成され、その後、既存のすべての要素のコピー/転送のコンストラクターによって、ピースごとに別のピースが作成されます。 つまり、オブジェクトのクラスに転送コンストラクターを追加したくない場合は、動作が非常に遅くなります。

そのため、この種のバッファにオブジェクトを格納するためにプールを書き換えます:



 template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };
      
      



= template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



-理由 template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class Factory { public: inline T* get(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ array = new T[num]; size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ delete []array; } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };







あなたが見ることができるように - クラスバッファは、コピーコンストラクタを持っています。 std :: vectorが配列の再割り当てを実行することを決定した場合に必要です。

その結果は - 最初の初期化のプールは、ほぼ倍に加速しました。



最後の仕上げ-さまざまな新しいコマンドを使用して、バッファーにメモリを割り当て、実際にコンストラクターを呼び出すプロセスを共有します。 「汚れていない」オブジェクトを取得するために、そして第二に、デフォルトコンストラクタなしでオブジェクトの使用を許可する - ということは、結果として、まず第一に、私たちを可能にします。



結果
 template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };
      
      



= template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



引数){ template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



)。 template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };



{ template <typename T, unsigned int chunk_size = 100> class PoolFactory { public: template<typename... Args> inline T* get(Args&&...args){ T* obj = getRaw(); new (obj) T(args...); return obj; } inline T* getRaw(){ if(free_ptrs.empty()){ makeMore(); } T* obj = free_ptrs.back(); free_ptrs.pop_back(); return obj; } inline void free(T* obj){ free_ptrs.push_back(obj); } inline void clearPool(){ buffers.clear(); free_ptrs.clear(); } void freeAll(){ free_ptrs.clear(); int buf_count = buffers.size(); for (int buf_id = 0; buf_id < buf_count; ++buf_id) { Buffer &buf = buffers[buf_id]; for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } } private: /** * @brief Use this against std::vector - because * vector have linear size complexity on reserve. * NOT grow size, but whole size! */ struct Buffer{ T* array; int size; Buffer(int num = chunk_size){ // allocate, but not construct array = static_cast<T*> (::operator new (sizeof(T[num]))); size = num; } /** * @brief IMPORTANT! Due to ussage with vector must have it. * @param other */ Buffer(Buffer&& other) noexcept{ size = other.size; array = other.array; other.array = nullptr; } ~Buffer(){ if (array != nullptr){ // destructors for (int i = 0; i < size; ++i) { array[i].~T(); } // deallocate ::operator delete(array); } } }; std::vector<Buffer> buffers; std::vector<T*> free_ptrs; void makeMore(){ buffers.emplace_back(chunk_size); Buffer &buf = buffers.back(); for (int i = 0; i < buf.size; ++i) { free_ptrs.emplace_back(&buf.array[i]); } } };







私にとっての主なタスクは、これらの小さなオブジェクトでstd :: vectorをすばやく埋めることでした。 それから、テストはいくぶん具体的です。 私の場合は - 平等 - プールとemplace_backの充填。 プールを再利用する場合-自然にプールが勝ちます。

テスト
 class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }
      
      



class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }



{ class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }



{ class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }



{ class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }



{ class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }



; class BaseClass { public: BaseClass(){} BaseClass(int value){ s = value; } int getS(){ return s; } int s; int m[16]; }; std::vector< BaseClass > ar; std::vector< BaseClass* > ptr_ar; const unsigned int total = 1000000; int main(int argc, char *argv[]) { PoolFactory<BaseClass> bPool; ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ar.emplace_back(var); } qDebug()<<"1 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"2 : "<<timer.elapsed(); bPool.freeAll(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(bPool.get(var)); } qDebug()<<"3 : "<<timer.elapsed(); ptr_ar.clear(); ptr_ar.reserve(total); timer.start(); for (int var = 0; var < total; ++var) { ptr_ar.push_back(new BaseClass(var)); } qDebug()<<"4 : "<<timer.elapsed(); }





結論:

1:21

2:22

3:5

4:37



遠慮なく:

1:135(これは転送コンストラクタクラスBaseClassので充填不足)

2:22

3:4

4:38




All Articles