参考《boost程序库开发完全指南》
//pool_func_eg.h
#pragma once
#include<iostream>
#include<boost\pool\pool.hpp>
using namespace boost;
void eg();
void eg_object_pool();
void eg_construct();
void eg_singleton_pool();
//object_pool.coo
#include"pool_func_eg.h"
/*
object_pool的特殊之处是construct和destroy函数,这两个函数是object_pool的真正价值所在。
construct先调用malloc分配内存,然后再在内存块上使用传入的参数调用类的构造函数,返回的是一个已经初始化的对象指针(类似于make_shared)
destroy则先调用对象的析构函数,然后再用free释放内存块
*/
#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 eg_object_pool() {
object_pool<demo_class> p1; //对象内存池
demo_class * dc = p1.malloc(); //分配一个原始内存块
assert(p1.is_from(dc));
//dc指向的内存未经初始化
assert(dc->a != 1 || dc->b != 2 || dc->c != 3);
dc = p1.construct(2, 3, 4);
assert(dc->a == 2);
object_pool<std::string> p2;
for (int i = 0; i < 10 ; ++i) { //连续分配大量的string
std::string *ps = p2.construct("hello");
std::cout << *ps << std::endl;
}
} //所有对象都在这里被析构释放
/*
使用更多的构造参数:
construct默认最多只能使用3个参数创建对象,但constructor被设计为可扩展的
pool库在目录boost/pool/detail下提供了一个名为pool_construct.m4和pool_construct_simple.m4的脚本
并同时提供可在Unix/Linux和Windows下运行的同名sh和bat可执行脚本文件,只要简单的向批处理脚本传递一个整数参数N,
m4就能自动生成具有N个参数的construct源码
*/
/*
自定义扩展construct,若临时的想要扩展参数的数量,可以自定义一个construct函数
下面代码模仿construct函数实现了一个可接受4个参数的创建函数
*/
struct demo_class1 { //一个示范用的类
public:
int a, b, c,d;
demo_class1(int x = 1, int y = 2, int z = 3,int u = 4) :a(x), b(y), c(z),d(u) {}
};
template<typename P,typename T0,typename T1,typename T2,typename T3>
inline typename P::element_type * construct(P &p, const T0 & a0, const T1 & a1, const T2& a2, const T3& a3) {
typename P::element_type * mem = p.malloc();
assert(mem != 0);
new(mem)P::element_type(a0, a1, a2, a3); //定位new运算符
return mem;
}
void eg_construct() {
object_pool<demo_class1> op1;
demo_class1 * dc1 = construct(op1, 2, 3, 4, 5);
std::cout << dc1->a << " " << dc1->b << std::endl;
}
//singleton_pool.cpp
#include"pool_func_eg.h"
/*
singleton_pool与pool的接口完全一致,可以分配简单数据类型的内存指针,但它是一个单件,并提供线程安全
*/
#include<boost/pool/singleton_pool.hpp>
/*
singleton_pool的成员函数均是静态的,因此不会产生single_ton的实例,调用函数的时候直接用域操作符
所以它的生命周期与整个程序一样长,除非手动调用release_memory或purge_memory,否则singleton_pool不会自动释放占用的内存
*/
struct pool_tag{}; //空类,仅仅用于标记
typedef singleton_pool<struct pool_tag, sizeof(int)> sp; //内存池定义
void eg_singleton_pool() {
int *p = (int *)sp::malloc(); //分配内存块
assert(sp::is_from(p));
sp::release_memory();
}
//Mainpool.cpp
//用来测试各个cpp中的函数
/*
pool库基于简单的分隔存储思想实现了一个简单的内存池库,不仅能够管理大量的对象,还可以用作STL的内存分配器
pool库包含4个部分:最简单的pool,分配类实例的object_pool,单件内存池singleton_pool,可用于标准库的pool_alloc
*/
#include"pool_func_eg.h"
/*
pool的模板类型参数UserAllocator是一个用户定义的内存分配器,它实现了特定的内存分配算法,通常
可以直接用默认的default_user_allocator_new_delete
pool的构造函数接受一个size_type类型的整数request_size只是每次pool分配内存块的大小(不是内存池的大小)
在析构时,pool将自动释放内存
成员函数malloc和ordered_malloc的行为更类似于C中的全局函数malloc,void*指针返回从内存池中分配的内存块
大小为构造函数中指定的requested_size如果分配失败,函数返回0,不会抛出异常
malloc从内存池中任意分配一个内存块,order_malloc则在分配的同时合并空闲块链表。
order_malloc带参数的形式还可以连续分配n快的内存,分配后的内存块可以用is_from函数测试是否是从这个内存池分配出去的
与malloc对应的函数是free,用来手工释放之前分配的内存块,这些内存块必须是从这个内存池分配出去的
一般情况下内存池会自动管理内存分配,不应该调用free函数,除非你认为内存池的空间已经不足,必须释放已经分配的内存
还有两个成员函数release_memory让内存池释放所有未被分配的内存,已分配的内存不受影响
purge_memory则强制释放内存池持有的所有内存,这两个函数一般情况下也不应该手工调用
*/
//example for pool
//pool只能用于int double 等类型的内存池
void eg_pool() {
pool<> p(sizeof(int)); //一个可分配int的内存池
int *p1 = (int *)p.malloc(); //必须把void*类型转换为需要的类型
assert(p.is_from(p1));
p.free(p1); //释放内存池分配的内存块
for (int i = 0; i < 100; ++i) { //连续分配大量内存
p.ordered_malloc(10); //pool在分配内存的时候不会抛出异常,所以实际编写的代码应该检查返回的指针是否为空
}
} //内存池对象析构,所有分配的内存在这里都被释放
int main() {
eg_object_pool();
eg_construct();
eg_singleton_pool();
return 0;
}