????? C/C++ 最容易出问题的地方是内存管理,容易造成内存泄露和内存越界,一直是 C/++ 程序员比较容易出错而且比较头疼的事情,但 C/C++ 最大的优势也是内存管理,可以让程序员直接管理内存,从而实现高效的内存管理,acl 库中的对象内存池管理器 acl::dbuf_guard 在管理内存的效率上比系统级内存管理(malloc/free, new/delete)更为高效,同时也提高了内存管理的安全性,可以使 C/C++ 程序员避免出现内存问题。本节主要介绍了 acl 库中 dbuf_guard 类的使用方法。
????? dbuf_guard 类内部封装了内存池对象类 dbuf_pool,提供了与 dbuf_pool 一样的内存分配方法,dbuf_guard类 与 dbuf_pool 类的最大区别是 dbuf_guard 类对象既可以在堆上动态分配,也可以在栈上分配,而 dbuf_pool 类对象必须在堆上动态分配,另外,dbuf_guard 类还统一管理在 dbuf_pool 内存池上所创建的所有 dbuf_obj 子类对象,在 dbuf_guard 类对象析构时,所有由其管理的 dbuf_obj 子类对象被统一析构。首先从一个简单的例子来说明 dbuf_guard 的使用方法,例子如下:
void test(void) { // 定义一个内存池管理对象 acl::dbuf_guard dbuf; #define STR "hello world" // 在 dbuf 对象上动态创建一个字符串内存 char* str = dbuf.dbuf_strdup(STR); printf("str: %s\r\n", str); // 在 dbuf 对象上动态创建内存 // sizeof(STR) 取得 STR 所包含的字符串长度 + 1 str = (char*) dbuf.dbuf_alloc(sizeof(STR)); memcpy(str, STR, sizeof(STR)); printf("str: %s\r\n", str); // 在本函数返回前,dbuf 对象自动被销毁,同时释放其所管理的 // 内存池以及在内存池上分配的内存 }
?????? 上面的例子展示了使用 dbuf_guard 类对象直接分配内存块的过程,可以看出所有在 dbuf_guard 的内存池上动态分配的内存都会在 dbuf_guard 对象销毁时被自动释放。这只是一个简单的使用 dbuf_guard 进行内存管理的例子,下面介绍 C++ 对象在 dbuf_guard 创建的例子:
class myobj : public acl::dbuf_obj { public: myobj() { str_ = strdup("hello world"); } void run() { printf("str: %s\r\n", str_); } private: char* str_; ~myobj() { free(str_); } }; void test(void) { acl::dbuf_guard dbuf; // 创建 myobj 对象时给 new 操作符传入在 dbuf_guard 对象的内存池上分配的内存 myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(); // 将 obj 对象交由 dbuf 统一管理 dbuf.push_back(obj); // 调用 myobj::run 方法 obj->run(); // 本函数返回前,dbuf 对象被销毁,obj 一起被销毁 }
?????? 该例子展示了 C++ 对象在 dbuf_guard 动态创建的过程,其中有三个要点:
????? 1、由 dbuf_guard 对象统一管理的 C++ 对象必须是 acl::dbuf_obj 的子类,这样在 dbuf_guard 类对象的析构里才可以通过调用 dbuf_obj 的析构函数来达到将 dbuf_obj 子类析构的目的;
????? 2、创建 dbuf_obj 的子类 myobj 对象时,通过给 C++? new 操作符传入了在 dbuf_guard 类对象分配的内存,从而实现了将 myobj 对象创建在 dbuf_guard 所管理的内存池上的目的;
????? 3、所创建的 acl::dbuf_obj 子类对象需要通过 acl::dbuf_guard::push_back(acl::dbuf_obj*) 方法实现了统一管理,这样在 dbuf_guard 对象析构时,这些 acl::dbuf_obj 的子类对象一起被析构。
?
????? 当然,除了上面的要点 3 所提到的将 acl::dbuf_obj 子类对象进行管理的方法外,还有一种方法:通过子类对象的构造函数将 acl::dbuf_guard 对象指针传递给 acl::dbuf_obj 的构造函数,实现 acl::dbuf_obj 子类对象的统一管理(在 acl::dbuf_ojb 的构造函数内部,当判断参数 acl::dbuf_guard 的对象指针非 NULL 时,会自动调用 acl::dbuf_guard::push_back 方法)。该简单例子如下:
// 继承于 acl::dbuf_obj 类 class myobj : public acl::dbuf_obj { public: // 将 acl::dbuf_guard 对象指针传递给基类 acl::dbuf_obj myobj(acl::dbuf_guard* dbuf) : dbuf_obj(dbuf) { str_ = strdup("hello world"); } void run() { printf("str: %s\r\n", str_); } private: char* str_; ~myobj() { free(str_); } }; void test(void) { acl::dbuf_guard dbuf; // 创建 myobj 对象时给 new 操作符传入在 dbuf_guard 对象的内存池上分配的内存 myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(&dbuf); // 调用 myobj::run 方法 obj->run(); // 本函数返回前,dbuf 对象被销毁,obj 一起被销毁 }
?
????? 在 acl::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);
?
????? 最后,以一个稍微复杂的例子做为结尾,该例子展示了使用 acl::dbuf_guard 类对象创建 C++ 动态对象的几种方式:
#include "stdafx.h" #include <sys/time.h> /** * dbuf_obj 子类,在 dbuf_pool 上动态分配,由 dbuf_guard 统一进行管理 */ class myobj : public acl::dbuf_obj { public: myobj(acl::dbuf_guard* guard) : dbuf_obj(guard) { ptr_ = strdup("hello"); } void run() { printf("----> run->hello world <-----\r\n"); } private: char* ptr_; // 将析构声明为私人,以强制要求该对象被动态分配,该析构函数将由 // dbuf_guard 统一调用,以释放本类对象中产生的动态内存(ptr_) ~myobj() { free(ptr_); } }; static void test_dbuf(acl::dbuf_guard& dbuf) { for (int i = 0; i < 102400; i++) { // 动态分配内存 char* ptr = (char*) dbuf.dbuf_alloc(10); (void) ptr; } for (int i = 0; i < 102400; i++) { // 动态分配字符串 char* str = dbuf.dbuf_strdup("hello world"); if (i < 5) printf(">>str->%s\r\n", str); } // 动态分配内存 (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(2048); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(1024); (void) dbuf.dbuf_alloc(10240); for (int i = 0; i < 10000; i++) { // 动态分配 dbuf_obj 子类对象,并通过将 dbuf_guard 对象传入 // dbuf_obj 的构造函数,从而将之由 dbuf_guard 统一管理, myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(&dbuf); // 验证 dbuf_obj 对象在 dbuf_guard 中的在在一致性 assert(obj == dbuf[obj->pos()]); // 调用 dbuf_obj 子类对象 myobj 的函数 run if (i < 10) obj->run(); } for (int i = 0; i < 10000; i++) { myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(NULL); int pos = dbuf.push_back(obj); assert(dbuf[pos] == obj); if (i < 10) obj->run(); } for (int i = 0; i < 10000; i++) { myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(&dbuf); // 虽然多次将 dbuf_obj 对象置入 dbuf_guard 中,因为 dbuf_obj // 内部的引用计数,所以可以防止被重复添加 (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); assert(obj == dbuf[obj->pos()]); if (i < 10) obj->run(); } for (int i = 0; i < 10000; i++) { myobj* obj = new (dbuf.dbuf_alloc(sizeof(myobj))) myobj(NULL); (void) dbuf.push_back(obj); // 因为 dbuf_guard::push_back 内部有防止重复添加的机制, // 所以下面多次添加虽然多余,但并不会有害 (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); (void) dbuf.push_back(obj); int pos = dbuf.push_back(obj); assert(dbuf[pos] == obj); if (i < 10) obj->run(); } } static void wait_pause() { printf("Enter any key to continue ..."); fflush(stdout); getchar(); } static void test1() { // dbuf_gaurd 对象创建在栈上,函数返回前该对象自动销毁 acl::dbuf_guard dbuf; test_dbuf(dbuf); } static void test2() { // 动态创建 dbuf_guard 对象,需要手动销毁该对象 acl::dbuf_guard* dbuf = new acl::dbuf_guard; test_dbuf(*dbuf); // 手工销毁该对象 delete dbuf; } static void test3() { // 将内存池对象 dbuf_pool 做为 dbuf_guard 构造函数参数传入,当 // dbuf_guard 对象销毁时,dbuf_pool 对象一同被销毁 acl::dbuf_guard dbuf(new acl::dbuf_pool); test_dbuf(dbuf); } static void test4() { // 动态创建 dbuf_guard 对象,同时指定内存池中内存块的分配倍数为 10, // 即指定内部每个内存块大小为 4096 * 10 = 40 KB,同时 // 指定内部动态数组的初始容量大小 acl::dbuf_guard dbuf(10, 100); test_dbuf(dbuf); } static void test5() { acl::dbuf_pool* dp = new acl::dbuf_pool; // 在内存池对象上动态创建 dbuf_guard 对象,这样可以将内存分配的次数 // 进一步减少一次 acl::dbuf_guard* dbuf = new (dp->dbuf_alloc(sizeof(acl::dbuf_guard))) acl::dbuf_guard(dp); test_dbuf(*dbuf); // 因为 dbuf_gaurd 对象也是在 dbuf_pool 内存池对象上动态创建的,所以 // 只能通过直接调用 dbuf_guard 的析构函数来释放所有的内存对象; // 既不能直接 dbuf_pool->desotry(),也不能直接 delete dbuf_guard 来 // 销毁 dbuf_guard 对象 dbuf->~dbuf_guard(); } int main(void) { acl::log::stdout_open(true); test1(); wait_pause(); test2(); wait_pause(); test3(); wait_pause(); test4(); wait_pause(); test5(); return 0; }
????? 上面例子在 acl 库中的位置:lib_acl_cpp\samples\dbuf\dbuf2
?
原文地址: http://zsxxsz.iteye.com/blog/2256868
svn:svn checkout svn://svn.code.sf.net/p/acl/code/trunk acl-code
github:git clone https://github.com/zhengshuxin/acl
sourceforge:http://sourceforge.net/projects/acl/
国内镜像:http://git.oschina.net/zsxxsz/acl/tree/master
qq 群:242722074
?
?
原文:http://zsxxsz.iteye.com/blog/2256868