Boost Development Guide - 3.9 object_pool

object_pool

object_pool is a memory pool for class instances (objects). Its function is similar to pool, but it will call the destructor for all allocated memory blocks during destructing, so as to release resources correctly.

object_pool is located in the namespace boost. In order to use the object_pool component, you need to include the header file <boost/pool/object_pool .hpp>, namely:

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

class summary

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

operation function

object_pool is a subclass of pool, but it uses protected inheritance, so the interface of pool cannot be used, but the basic operation is still very similar.

The template type parameter T of object_pool specifies the element type to be allocated by object_pool, and its destructor cannot throw an exception. Once the type is specified in the template, the object_pool instance can no longer be used to allocate objects of other types.

The malloc() and free() functions allocate and release a memory block of type T* respectively. Similarly, is_from() can be used to test the ownership of the memory block. Only the memory allocated by this memory pool can be released by free(). But they do not call the constructor and destructor of the class when they are called, that is to say, they operate on a piece of raw memory, and the value inside is undefined, so we should use malloc() and free() as little as possible .

The special feature of object_pool is the construct() and destroy() functions, these two functions are the real value of object_pool. construct() is actually a set of functions with overloaded forms with multiple parameters (currently supports up to 3 parameters, but can be extended), it first calls malloc() to allocate memory, and then uses the incoming The parameter calls the constructor of the class and returns an initialized object pointer. destroy() first calls the destructor of the object, and then frees the memory block with free().

None of these functions throw exceptions, and will return 0 if memory allocation fails.

usage

The usage of object_pool is also very simple. We can either allocate raw memory blocks like pool, or use construct() to directly create objects in the memory pool. Of course, the latter method of use is the most convenient.

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

use more constructor parameters

By default, when using object_pool's construct(), we can only use up to 3 parameters to create objects. This is enough in most cases, but sometimes we may define a constructor with more than 3 parameters, at which time the default overloaded form of construct() cannot be used.

Unfortunately, construct() did not follow up in time for the C++11 standard to support construction with any number of arguments using variadic templates. It implements a flexible extension mechanism based on the macro preprocessing m4 (usually comes with the UNIX system, and there is also a windows version), which can generate the construct() function code that accepts any number of parameters.

The pool library provides a script named pool_construct.m4 and pool_construct_simple.m4 under the directory /boost/pool/detail, and also provides sh and bat executable script files with the same name that can run under UNIX and windows. Simply pass an integer parameter N to the batch script, and m4 will automatically generate the source code for the construct() function with N parameters.

For example, under Linux, execute the command:

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

Two .ipp files with the same name will be generated, which contain the new construct() function definition, which can support up to 5 parameters to create objects.

The solution of m4 is rather clumsy. Using the variable parameter template feature of c++11, we can define an auxiliary template function that supports any number of parameters and completely solve this problem:

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

The free function construct() accepts any number of parameters. The first is the object_pool object, followed by the parameters required to create the object. The type of object to be created can be obtained by using the internal type definition element_type of object_pool. The function first calls malloc() to allocate a block of memory, and then calls the less common "placement new expression" (placement new expression) to create an object.

Suppose we have a class with a 4-argument constructor as follows:

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

Then the code to create an object using a custom construct() is:

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

code example

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

insert image description here

Guess you like

Origin blog.csdn.net/qq_36314864/article/details/132062753