オブジェクトプール
object_pool はクラス インスタンス (オブジェクト) のメモリ プールであり、その機能は pool と似ていますが、リソースを正しく解放するために、デストラクト中に割り当てられたすべてのメモリ ブロックに対してデストラクタを呼び出します。
object_pool は名前空間 boost にあります。object_pool コンポーネントを使用するには、<boost/pool/object_pool .hpp>
次のヘッダー ファイルをインクルードする必要があります。
#include <boost/pool/object_pool.hpp>
using namespace boost;
授業の概要
template <typename T, typename UserAllocator>
class object_pool : protected pool<UserAllocator>
{
public:
typedef T element_type;
public:
object_pool(); //构造函数
~object_pool(); //析构函数
element_type * malloc(); //分配内存
void free(element_type * p); //归还内存
bool is_from(element_type * p) const;
element_type * construct(...); //创建对象
void destroy(element_type * p); //销毁对象
};
操作機能
object_pool は pool のサブクラスですが、保護された継承を使用するため、pool のインターフェイスは使用できませんが、基本的な操作は非常に似ています。
object_pool のテンプレート タイプ パラメーター T は、object_pool によって割り当てられる要素のタイプを指定し、そのデストラクターは例外をスローできません。テンプレートでタイプを指定すると、object_pool インスタンスを使用して他のタイプのオブジェクトを割り当てることはできなくなります。
malloc() 関数と free() 関数は、タイプ T* のメモリ ブロックをそれぞれ割り当ておよび解放します。同様に、is_from() を使用してメモリ ブロックの所有権をテストできます。このメモリ プールによって割り当てられたメモリのみを解放できます。無料()。ただし、呼び出されたときにクラスのコンストラクターとデストラクターは呼び出されません。つまり、操作は元のメモリ ブロックの一部であり、内部の値は未定義であるため、malloc() と free() を次のように使用する必要があります。できるだけ少なく。
object_pool の特別な機能は、construct() 関数と destroy() 関数であり、これら 2 つの関数が object_pool の実際の値です。construct() は、実際には、複数のパラメータを持つオーバーロードされた形式を持つ関数のセットです (現在は最大 3 つのパラメータをサポートしていますが、拡張することができます)。最初に malloc() を呼び出してメモリを割り当て、次に受信したパラメータを使用して、次のコンストラクタを呼び出します。クラスを取得し、初期化されたオブジェクト ポインタを返します。destroy() は最初にオブジェクトのデストラクターを呼び出し、次に free() でメモリ ブロックを解放します。
これらの関数はいずれも例外をスローせず、メモリ割り当てが失敗した場合は 0 を返します。
使用法
object_pool の使用法も非常に簡単で、プールのように生のメモリ ブロックを割り当てるか、construct() を使用してメモリ プール内にオブジェクトを直接作成できます。もちろん、後者の使用方法が最も便利です。
#include <boost/pool/object_pool.hpp>
struct demo_class //一个示范用的类
{
public:
int a, b, c;
demo_class(int x = 1, int y = 2, int z = 3) :
a(x), b(y), c(z) {
}
};
int main()
{
object_pool<demo_class> pl; //对象内存池
auto p = pl.malloc(); //分配一个原始内存块
assert(pl.is_from(p));
assert(p->a != 1 || p->b != 2 || p->c != 3);
p = pl.construct(7, 8, 9); //构造一个对象,可以传递参数
assert(p->a == 7);
object_pool<string> pls; //定义一个分配string对象的内存池
for (int i = 0; i < 10; ++i) //连续分配大量string对象
{
string* ps = pls.construct("hello object_pool");
cout << *ps << endl;
}
} //所有创建的对象在这里都被正确析构、释放内存
より多くのコンストラクター パラメーターを使用する
デフォルトでは、object_pool のconstruct()を使用する場合、オブジェクトの作成に使用できるパラメーターは最大 3 つまでです。ほとんどの場合はこれで十分ですが、場合によっては 3 つを超えるパラメーターを持つコンストラクターを定義することがあります。その場合、construct() のデフォルトのオーバーロード形式は使用できません。
残念ながら、construct() は、C++11 標準で可変個引数テンプレートを使用した任意の数の引数による構築をサポートするのに間に合いませんでした。これは、マクロ前処理 m4 (通常は UNIX システムに付属しており、Windows バージョンもあります) に基づいた柔軟な拡張メカニズムを実装しており、任意の数のパラメーターを受け入れる construct() 関数コードを生成できます。
プール ライブラリは、ディレクトリ /boost/pool/detail の下に pool_construct.m4 および pool_construct_simple.m4 という名前のスクリプトを提供します。また、UNIX および Windows で実行できる同じ名前の sh および Bat 実行可能スクリプト ファイルも提供します。整数パラメーター N をバッチ スクリプトに渡すだけで、m4 は N パラメーターを含むconstruct() 関数のソース コードを自動的に生成します。
たとえば、Linux では次のコマンドを実行します。
./pool_construct_simple.sh 5; ./ pool_construct.sh 5
同じ名前の 2 つの .ipp ファイルが生成されます。これらのファイルには、オブジェクトを作成するための最大 5 つのパラメーターをサポートできる新しいconstruct() 関数定義が含まれています。
m4 の解決策はやや不器用ですが、C++11 の可変パラメーター テンプレート機能を使用すると、任意の数のパラメーターをサポートする補助テンプレート関数を定義して、この問題を完全に解決できます。
template<typename P, typename ... Args> //C++11可变参数模板
inline typename P::element_type*
construct(P& p, Args&& ... args)
{
typename P::element_type* mem = p.malloc();
assert(mem != 0);
new (mem) typename P::element_type(
std::forward<Args>(args)...); //C++11的完美转发
return mem;
}
無料の関数construct()は、任意の数のパラメータを受け入れます。最初はobject_poolオブジェクトで、次にオブジェクトの作成に必要なパラメータが続きます。作成されるオブジェクトのタイプは、object_poolの内部型定義element_typeを使用して取得できます。この関数は、まず malloc() を呼び出してメモリ ブロックを割り当て、次にあまり一般的ではない「placement new 式」(placement new 式) を呼び出してオブジェクトを作成します。
次のような 4 引数のコンストラクターを持つクラスがあるとします。
struct demo_class
{
demo_class2(int, int, int, int) //构造函数接受4个参数
{
cout << "demo_class ctor" << endl;
}
~demo_class2()
{
cout << "demo_class dtor" << endl;
}
};
次に、カスタムconstruct()を使用してオブジェクトを作成するコードは次のとおりです。
object_pool<demo_class> p1;
auto d = construct(p1,1,2,3,4);
コード例
#include <iostream>
using namespace std;
#include <boost/core/ignore_unused.hpp>
//#define BOOST_SYSTEM_NO_DEPRECATED
//#define BOOST_POOL_NO_MT
#include <boost/pool/pool.hpp>
using namespace boost;
#include <boost/pool/object_pool.hpp>
struct demo_class
{
public:
int a, b, c;
demo_class(int x = 1, int y = 2, int z = 3) :
a(x), b(y), c(z) {
}
};
void case2()
{
object_pool<demo_class> pl;
auto p = pl.malloc();
assert(pl.is_from(p));
assert(p->a != 1 || p->b != 2 || p->c != 3);
p = pl.construct(7, 8, 9);
assert(p->a == 7);
object_pool<string> pls;
for (int i = 0; i < 10; ++i)
{
string* ps = pls.construct("hello object_pool");
cout << *ps << endl;
}
}
//
template<typename P, typename ... Args>
inline typename P::element_type*
construct(P& p, Args&& ... args)
{
typename P::element_type* mem = p.malloc();
assert(mem != 0);
new (mem) typename P::element_type(
std::forward<Args>(args)...);
return mem;
}
struct demo_class2
{
demo_class2(int, int, int, int)
{
cout << "demo_class ctor" << endl;
}
~demo_class2()
{
cout << "demo_class dtor" << endl;
}
};
void case3()
{
object_pool<demo_class2> pl;
auto d = construct(pl, 1, 2, 3, 4);
boost::ignore_unused(d);
}
int main()
{
case2();
case3();
}