#pragma once #include "acl_cpp/acl_cpp_define.hpp" #include struct ACL_DBUF_POOL; namespace acl { /** * 会话类的内存链管理类,该类仅提供内存分配函数,在整个类对象被析构时该内存链 * 会被一次性地释放,该类适合于需要频繁分配一些大小不等的小内存的应用; * 该类实际上是封装了 lib_acl 中的 ACL_DBUF_POOL 结构及方法 */ class ACL_CPP_API dbuf_pool { public: /** * 该类对象必须动态创建 */ dbuf_pool(); /** * 该类对象必须要动态创建,所以隐藏了析构函数,使用者需要调用 destroy * 函数来销毁动态对象 */ void destroy(); /** * 重载 new/delete 操作符,使 dbuf_pool 对象本身也创建在内存池上, * 从而减少了 malloc/free 的次数 * @param size {size_t} 由编译传入的 dbuf_pool 对象的长度大小 * @param nblock {size_t} 内部采用的内存块(4096)的倍数 */ void *operator new(size_t size, size_t nblock = 2); #if defined(_WIN32) || defined(_WIN64) void operator delete(void* ptr, size_t); #else void operator delete(void* ptr); #endif /** * 重置内存池的状态以便于重复使用该内存池对象 * @param reserve {size_t} 若该值 > 0,则需要指定额外保留的内存大小, * 该大小必须小于等于已经在该内存池对象分配的大小 * @return {bool} 如果输入参数非法,则返回 false */ bool dbuf_reset(size_t reserve = 0); /** * 分配指定长度的内存 * @param len {size_t} 需要分配的内存长度,当内存比较小时(小于构造函数 * 中的 block_size)时,所分配的内存是在 dbuf_pool 所管理的内存链上, * 当内存较大时会直接使用 malloc 进行分配 * @return {void*} 新分配的内存地址 */ void* dbuf_alloc(size_t len); /** * 分配指定长度的内存并将内存区域清零 * @param len {size_t} 需要分配的内存长度 * @return {void*} 新分配的内存地址 */ void* dbuf_calloc(size_t len); /** * 根据输入的字符串动态创建新的内存并将字符串进行复制,类似于 strdup * @param s {const char*} 源字符串 * @return {char*} 新复制的字符串地址 */ char* dbuf_strdup(const char* s); /** * 根据输入的字符串动态创建新的内存并将字符串进行复制,类似于 strdup * @param s {const char*} 源字符串 * @param len {size_t} 限制所复制字符串的最大长度 * @return {char*} 新复制的字符串地址 */ char* dbuf_strndup(const char* s, size_t len); /** * 根据输入的内存数据动态创建内存并将数据进行复制 * @param addr {const void*} 源数据内存地址 * @param len {size_t} 源数据长度 * @return {void*} 新复制的数据地址 */ void* dbuf_memdup(const void* addr, size_t len); /** * 归还由内存池分配的内存 * @param addr {const void*} 由内存池分配的内存地址 * @return {bool} 如果该内存地址非内存池分配或释放多次,则返回 false */ bool dbuf_free(const void* addr); /** * 保留由内存池分配的某段地址,以免当调用 dbuf_reset 时被提前释放掉 * @param addr {const void*} 由内存池分配的内存地址 * @return {bool} 如果该内存地址非内存池分配,则返回 false */ bool dbuf_keep(const void* addr); /** * 取消保留由内存池分配的某段地址,以便于调用 dbuf_reset 时被释放掉 * @param addr {const void*} 由内存池分配的内存地址 * @return {bool} 如果该内存地址非内存池分配,则返回 false */ bool dbuf_unkeep(const void* addr); /** * 获得内部 ACL_DBUF_POOL 对象,以便于操作 C 接口的内存池对象 * @return {ACL_DBUF_POOL*} */ ACL_DBUF_POOL *get_dbuf() { return pool_; } private: ACL_DBUF_POOL* pool_; size_t mysize_; public: ~dbuf_pool(); }; /** * sample: * void test() * { * acl::dbuf_pool* dbuf = new acl::dbuf_pool; * for (int i = 0; i < 1000; i++) * { * char* ptr = dbuf->dbuf_strdup("hello world!"); * printf("%s\r\n", p); * } * dbuf->destroy(); * * // 创建 dbuf 对象时,指定了内部分配内存块的位数 * dbuf = new(8) acl::dbuf_pool; * for (int i = 0; i < 1000; i++) * { * ptr = dbuf->dbuf_strdup("hello world!"); * printf("%s\r\n", p); * } * * // 销毁 dbuf 对象 * dbuf->destroy(); * } * */ ////////////////////////////////////////////////////////////////////////////// class dbuf_guard; /** * 在会话内存池对象上分配的对象基础类 */ class ACL_CPP_API dbuf_obj { public: /** * 构造函数 * @param guard {dbuf_guard*} 该参数非空时,则本类的子类对象会被 * dbuf_guard 类对象自动管理,统一销毁;如果该参数为空,则应用应 * 调用 dbuf_guard::push_back 方法将子类对象纳入统一管理 */ dbuf_obj(dbuf_guard* guard = NULL); virtual ~dbuf_obj() {} /** * 获得该对象在 dbuf_guard 中的数组中的下标位置 * @return {int} 返回该对象在 dbuf_guard 中的数组中的下标位置,当该 * 对象没有被 dbuf_guard 保存时,则返回 -1,此时有可能会造成内存泄露 */ int pos() const { return pos_; } /** * 返回构造函数中 dbuf_guard 对象 * @return {dbuf_guard*} */ dbuf_guard* get_guard() const { return guard_; } private: friend class dbuf_guard; // 记录本对象所属的 dbuf_guard 对象 dbuf_guard* guard_; // 该变量便于 dbuf_guard 对象使用,以增加安全性 int nrefer_; // 该对象在 dbuf_guard 对象中记录的数组的位置 int pos_; }; /** * 会话内存池管理器,由该类对象管理 dbuf_pool 对象及在其上分配的对象,当该类 * 对象销毁时,dbuf_pool 对象及在上面均被释放。 */ class ACL_CPP_API dbuf_guard { public: /** * 构造函数 * @param dbuf {dbuf_pool*} 当该内存池对象非空时,dbuf 将由 dbuf_guard * 接管,如果为空,则本构造函数内部将会自动创建一个 dbuf_pool 对象 * @param capacity {size_t} 内部创建的 objs_ 数组的初始长度 */ dbuf_guard(dbuf_pool* dbuf, size_t capacity = 100); /** * 构造函数 * @param nblock {size_t} 本类对象内部创建 dbuf_pool 对象时,本参数 * 指定了内存块(4096)的倍数 * @param capacity {size_t} 内部创建的 objs_ 数组的初始长度 */ dbuf_guard(size_t nblock = 2, size_t capacity = 100); /** * 析构函数,在析构函数内部将会自动销毁由构造函数传入的 dbuf_pool 对象 */ ~dbuf_guard(); /** * 调用 dbuf_pool::dbuf_reset * @param reserve {size_t} * @return {bool} */ bool dbuf_reset(size_t reserve = 0) { return dbuf_->dbuf_reset(reserve); } /** * 调用 dbuf_pool::dbuf_alloc * @param len {size_t} * @return {void*} */ void* dbuf_alloc(size_t len) { return dbuf_->dbuf_alloc(len); } /** * 调用 dbuf_pool::dbuf_calloc * @param len {size_t} * @return {void*} */ void* dbuf_calloc(size_t len) { return dbuf_->dbuf_calloc(len); } /** * 调用 dbuf_pool::dbuf_strdup * @param s {const char*} * @return {char*} */ char* dbuf_strdup(const char* s) { return dbuf_->dbuf_strdup(s); } /** * 调用 dbuf_pool::dbuf_strndup * @param s {const char*} * @param len {size_t} * @return {char*} */ char* dbuf_strndup(const char* s, size_t len) { return dbuf_->dbuf_strndup(s, len); } /** * 调用 dbuf_pool::dbuf_memdup * @param addr {const void*} * @param len {size_t} * @return {void*} */ void* dbuf_memdup(const void* addr, size_t len) { return dbuf_->dbuf_memdup(addr, len); } /** * 调用 dbuf_pool::dbuf_free * @param addr {const void*} * @return {bool} */ bool dbuf_free(const void* addr) { return dbuf_->dbuf_free(addr); } /** * 调用 dbuf_pool::dbuf_keep * @param addr {const void*} * @return {bool} */ bool dbuf_keep(const void* addr) { return dbuf_->dbuf_keep(addr); } /** * 调用 dbuf_pool::dbuf_unkeep * @param addr {const void*} * @return {bool} */ bool dbuf_unkeep(const void* addr) { return dbuf_->dbuf_unkeep(addr); } /** * 获得 dbuf_pool 对象 * @return {acl::dbuf_pool&} */ acl::dbuf_pool& get_dbuf() const { return *dbuf_; } /** * 可以手动调用本函数,将在 dbuf_pool 上分配的 dbuf_obj 子类对象交给 * dbuf_guard 对象统一进行销毁管理;严禁将同一个 dbuf_obj 子类对象同 * 时将给多个 dbuf_guard 对象进行管理,否则将会产生对象的重复释放 * @param obj {dbuf_obj*} * @return {int} 返回 obj 被添加后其在 dbuf_obj 对象数组中的下标位置, * dbuf_guard 内部对 dbuf_obj 对象的管理具有防重添加机制,所以当多次 * 将同一个 dbuf_obj 对象置入同一个 dbuf_guard 对象时,内部只会放一次 */ int push_back(dbuf_obj* obj); /** * 获得当前内存池中管理的对象数量 * @return {size_t} */ size_t size() const { return size_; } /** * 获得当前内存池中管理的对象集合,该函数必须与 size() 函数配合使用, * 以免指针地址越界 * @return {dbuf_obj**} 返回 dbuf_obj 对象集合,永远返回非 NULL 值, * 该数组的大小由 size() 函数决定 */ dbuf_obj** get_objs() const { return objs_; } /** * 返回指定下标的对象 * @param pos {size_t} 指定对象的下标位置,不应越界 * @return {dbuf_obj*} 当下标位置越界时返回 NULL */ dbuf_obj* operator[](size_t pos) const; /** * 返回指定下标的对象 * @param pos {size_t} 指定对象的下标位置,不应越界 * @return {dbuf_obj*} 当下标位置越界时返回 NULL */ dbuf_obj* get(size_t pos) const; /** * 设置内建 objs_ 数组对象每次在扩充空间时的增量,内部缺省值为 100 * @param incr {size_t} */ void set_increment(size_t incr); public: template T* create() { T* t = new (dbuf_alloc(sizeof(T))) T(); (void) push_back(t); return t; } template T* create(P1 p) { T* t = new (dbuf_alloc(sizeof(T))) T(p); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4, p5); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4, p5, p6); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4, p5, p6, p7); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4, p5, p6, p7, p8); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4, p5, p6, p7, p8, p9); (void) push_back(t); return t; } template T* create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) { T* t = new (dbuf_alloc(sizeof(T))) T(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); (void) push_back(t); return t; } private: size_t nblock_; // 内部自建 dbuf_pool 内存块的单位个数 dbuf_pool* dbuf_; // 内存池对象 // 此处之所以使用自实现的 dbuf_obj 数组对象,而没有使用 std::vector, // 一方面使数组对象也在 dbuf_pool 内存池上创建,另一方面可以避免 // std::vector 内部在扩容时的内存不可控性 dbuf_obj** objs_; // 存储 dbuf_obj 对象的数组对象 size_t size_; // 存储于 objs_ 中的对象个数 size_t capacity_; // objs_ 数组的大小 size_t incr_; // objs_ 数组扩充时的增量个数 // 扩充 objs_ 数组对象的空间 void extend_objs(); }; /** * sample1: * // 继承 acl::dbuf_obj 的子类 * class myobj1 : public acl::dbuf_obj * { * public: * // 将 guard 对象传递给基类对象,基类将本对象加入 guard 的对象集合中 * myobj1(acl::dbuf_guard* guard) : dbuf_obj(guard) {} * * void doit() * { * printf("hello world!\r\n"); * } * * private: * ~myobj1() {} * }; * * void test() * { * acl::dbuf_guard dbuf; * * // 在 dbuf_guard 对象上创建动态 100 个 myobj 对象 * for (int i = 0; i < 100; i++) * { * // 在 guard 对象上创建动态 myobj 对象,且将 guard 作为构造参数 * myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(&dbuf); * obj->doit(); * } * * // 当 dbuf 销毁时,在其上面创建的动态对象自动销毁 * } * * // sample2 * class myobj2 : public acl::dbuf_obj * { * public: * myobj2() {} * * void doit() * { * printf("hello world\r\n"); * } * * private: * ~myobj2() {} * }; * * void test2() * { * acl::dbuf_guard dbuf; * * for (int i = 0; i < 100; i++) * { * myobj2* obj = dbuf.create(); * obj->doit(); * } * } * * // sample3 * class myobj2 : public acl::dbuf_obj * { * public: * myobj2(int i) : i_(i) {} * * void doit() * { * printf("hello world, i: %d\r\n", i_); * } * * private: * ~myobj2() {} * * private: * int i_; * }; * * void test2() * { * acl::dbuf_guard dbuf; * * for (int i = 0; i < 100; i++) * { * myobj2* obj = dbuf.create(i); * obj->doit(); * } * } */ } // namespace acl