Guide de développement Boost - 3.9 object_pool

object_pool

object_pool est un pool de mémoire pour les instances de classe (objets), sa fonction est similaire à pool, mais il appellera le destructeur de tous les blocs de mémoire alloués lors de la destruction, afin de libérer correctement les ressources.

object_pool est situé dans le boost de l'espace de noms. Pour utiliser le composant object_pool, vous devez inclure le fichier d'en-tête <boost/pool/object_pool .hpp>, à savoir :

#include <boost/pool/object_pool.hpp>
using namespace boost;

résumé de la classe

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); //销毁对象
};

fonction de fonctionnement

object_pool est une sous-classe de pool, mais il utilise un héritage protégé, de sorte que l'interface de pool ne peut pas être utilisée, mais le fonctionnement de base est toujours très similaire.

Le paramètre de type de modèle T de object_pool spécifie le type d'élément à allouer par object_pool, et son destructeur ne peut pas lever d'exception. Une fois le type spécifié dans le modèle, l'instance object_pool ne peut plus être utilisée pour allouer des objets d'autres types.

Les fonctions malloc() et free() allouent et libèrent respectivement un bloc mémoire de type T*. De même, is_from() peut être utilisé pour tester la propriété du bloc mémoire. Seule la mémoire allouée par ce pool mémoire peut être libérée par gratuit(). Mais ils n'appellent pas le constructeur et le destructeur de la classe lorsqu'ils sont appelés, c'est-à-dire que l'opération est un morceau de bloc de mémoire d'origine, la valeur à l'intérieur est indéfinie, nous devons donc utiliser malloc() et free() comme le moins possible.

La particularité d'object_pool est les fonctions construct() et destroy(), ces deux fonctions sont la valeur réelle d'object_pool. construct() est en fait un ensemble de fonctions avec des formulaires surchargés avec plusieurs paramètres (prend actuellement en charge jusqu'à 3 paramètres, mais peut être étendu), il appelle d'abord malloc() pour allouer de la mémoire, puis utilise le paramètre entrant Le paramètre appelle le constructeur de la classe et renvoie un pointeur d'objet initialisé. destroy() appelle d'abord le destructeur de l'objet, puis libère le bloc mémoire avec free().

Aucune de ces fonctions ne génère d'exceptions et renverra 0 si l'allocation de mémoire échoue.

usage

L'utilisation d'object_pool est également très simple, nous pouvons soit allouer des blocs de mémoire brute comme pool, soit utiliser construct() pour créer directement des objets dans le pool de mémoire. Bien sûr, cette dernière méthode d'utilisation est la plus pratique.

#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;
	}
} //所有创建的对象在这里都被正确析构、释放内存

utiliser plus de paramètres de constructeur

Par défaut, lors de l'utilisation de construct() d'object_pool, nous ne pouvons utiliser que 3 paramètres maximum pour créer des objets. Cela suffit dans la plupart des cas, mais parfois nous pouvons définir un constructeur avec plus de 3 paramètres, auquel cas la forme surchargée par défaut de construct() ne peut pas être utilisée.

Malheureusement, construct() n'a pas suivi à temps pour que le standard C++11 prenne en charge la construction avec n'importe quel nombre d'arguments à l'aide de modèles variadiques. Il implémente un mécanisme d'extension flexible basé sur le prétraitement de macro m4 (fourni généralement avec le système UNIX, et il existe également une version Windows), qui peut générer le code de la fonction construct() qui accepte n'importe quel nombre de paramètres.

La bibliothèque de pool fournit un script nommé pool_construct.m4 et pool_construct_simple.m4 sous le répertoire /boost/pool/detail, et fournit également des fichiers de script exécutables sh et bat portant le même nom qui peuvent s'exécuter sous UNIX et Windows. Passez simplement un paramètre entier N au script batch, et m4 générera automatiquement le code source de la fonction construct() avec N paramètres.

Par exemple, sous Linux, exécutez la commande :

./pool_construct_simple.sh 5; ./ pool_construct.sh 5

Deux fichiers .ipp portant le même nom seront générés, qui contiennent la nouvelle définition de fonction construct(), qui peut prendre en charge jusqu'à 5 paramètres pour créer des objets.

La solution de m4 est plutôt maladroite. En utilisant la fonctionnalité de modèle de paramètre variable de c++11, nous pouvons définir une fonction de modèle auxiliaire qui prend en charge n'importe quel nombre de paramètres et résoudre complètement ce problème :

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

La fonction libre construct() accepte n'importe quel nombre de paramètres. Le premier est l'objet object_pool, suivi des paramètres requis pour créer l'objet. Le type d'objet à créer peut être obtenu en utilisant la définition de type interne element_type de object_pool. La fonction appelle d'abord malloc() pour allouer un bloc de mémoire, puis appelle la moins courante "placement new expression" (placement new expression) pour créer un objet.

Supposons que nous ayons une classe avec un constructeur à 4 arguments comme suit :

struct demo_class
{
    
    
	demo_class2(int, int, int, int) //构造函数接受4个参数
	{
    
    
		cout << "demo_class ctor" << endl;
	}
	~demo_class2()
	{
    
    
		cout << "demo_class dtor" << endl;
	}
};

Ensuite, le code pour créer un objet à l'aide d'un construct() personnalisé est :

object_pool<demo_class> p1;
auto d = construct(p1,1,2,3,4);

exemple de code

#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();
}

insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/qq_36314864/article/details/132062753
conseillé
Classement