欢迎访问Lu程序设计
C/C++使用Lu键树实现智能指针及检查内存泄露
1 说明
要演示本文的例子,你必须下载Lu32脚本系统。本文的例子需要lu32.dll、lu32.lib、C++格式的头文件lu32.h,相信你会找到并正确使用这几个文件。
用C/C++编译器创建一个控制台应用程序,复制本文的例子代码直接编译运行即可。
2 关于智能指针及Lu实现
由于 C/C++ 语言没有自动内存回收机制,程序员每次 malloc/new 出来的内存都要手动 free/delete。由于程序流程太复杂,程序员容易忘记 free/delete,造成内存泄露。C++用智能指针可以有效缓解这类问题,例如:std::auto_ptr、boost::scoped_ptr、boost::shared_ptr、boost::scoped_array、boost::shared_array、boost::weak_ptr、boost::intrusive_ptr等等,可谓种类繁多。
实际上,C/C++程序使用Lu脚本的键树系统也可以解决此类问题,而且程序员可以方便地查找哪块内存忘记了free/delete。阅读完本文,你就可以尝试使用Lu脚本系统查找你的C/C++程序是否存在内存泄露了。
关于Lu脚本键树系统,可以参考Lu编程指南,同时参考这个教程:C/C++使用Lu脚本字符串键树。
3 代码
代码1:实现智能指针
#include#include #include "lu32.h" #pragma comment( lib, "lu32.lib" ) using namespace std; #define key_Simple (luPriKey_User-20) //将对该私有键加锁 #define imax 5 //私有键值最大数 void _stdcall Del_Simple(void *me); //销毁Simple的函数 class Simple //编写一个简单的类帮助测试 { public: int number; //数据 bool bDelete; //为帮助测试新增的数据,对象初始化时bDelete=false,对象销毁时bDelete=true Simple(int param=0) { //在类的初始化函数中增加以下几行代码 void *me,*NowKey=NULL; //为避免编译器发出警告进行初始化,实际上不需要 me=this; InsertKey((char *)&(me),sizeof(luVOID),key_Simple,this,Del_Simple,NULL,1,NowKey); //在Lu键树中注册键值 bDelete=false; number = param; cout << "Simple: " << number << endl; }; ~Simple() { //在类的初始化函数中增加以下几行代码 void *me; if(!bDelete) //如果用户手动delete { bDelete=true; me=this; DeleteKey((char *)&(me),sizeof(luVOID),key_Simple,Del_Simple,0); //在Lu键树中删除键值 } cout << "~Simple: " << number << endl; }; }; void _stdcall Del_Simple(void *me) //销毁Simple的函数,将注册到Lu 系统,以实现自动销毁Simple { Simple *pSimple; pSimple=(Simple*)me; if(pSimple->bDelete==false) //如果用户忘记了delete { pSimple->bDelete=true; delete pSimple; //这是Lu系统自动delete } } LuData _stdcall OpLock_Simple(luINT m,LuData *Para,void *hFor,int theOperator) //Simple的运算符重载函数 { LuData a; a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0; //不对Simple类型的对象做运算,总返回nil return a; } void main(void) { Simple *pSimple[imax]; int i; if(!InitLu()) return; //初始化Lu LockKey(key_Simple,Del_Simple,OpLock_Simple); //在Lu键树中加锁键,只能存储Simple类型 for(i=0;i
运行结果:Simple: 0
Simple: 1
Simple: 2
Simple: 3
Simple: 4
--- C++ delete 删除约1/2对象 ---
~Simple: 0
~Simple: 1
--- Lu系统解锁键并销毁全部对象 ---
~Simple: 2
~Simple: 4
~Simple: 3代码2:查找未释放对象(内存)
#include <windows.h> #include#include "lu32.h" #pragma comment( lib, "lu32.lib" ) using namespace std; #define key_Simple (luPriKey_User-20) //将对该私有键加锁 #define imax 5 //私有键值最大数 void _stdcall Del_Simple(void *me); //销毁Simple的函数 class Simple //编写一个简单的类帮助测试 { public: int number; //数据 bool bDelete; //为帮助测试新增的数据,对象初始化时bDelete=false,对象销毁时bDelete=true Simple(int param=0) { //在类的初始化函数中增加以下几行代码 void *me,*NowKey=NULL; //为避免编译器发出警告进行初始化,实际上不需要 me=this; InsertKey((char *)&(me),sizeof(luVOID),key_Simple,this,Del_Simple,NULL,1,NowKey); //在Lu键树中注册键值 bDelete=false; number = param; cout << "Simple: " << number << endl; }; ~Simple() { //在类的初始化函数中增加以下几行代码 void *me; if(!bDelete) //如果用户手动delete { bDelete=true; me=this; DeleteKey((char *)&(me),sizeof(luVOID),key_Simple,Del_Simple,0); //在Lu键树中删除键值 } cout << "~Simple: " << number << endl; }; }; void _stdcall Del_Simple(void *me) //销毁Simple的函数,将注册到Lu系统,以实现自动销毁Simple { Simple *pSimple; pSimple=(Simple*)me; if(pSimple->bDelete==false) //如果用户忘记了delete { pSimple->bDelete=true; delete pSimple; //这是Lu系统自动delete } } LuData _stdcall OpLock_Simple(luINT m,LuData *Para,void *hFor,int theOperator) //Simple的运算符重载函数 { LuData a; a.BType=luStaData_nil; a.VType=luStaData_nil; a.x=0; //不对Simple类型的对象做运算,总返回nil return a; } int _stdcall GetKeySimpleva lue(char *KeyStr,int ByteNum,void *KeyValue) //枚举Lu系统中指定键值类型的所有对象 { Simple *pSimple; pSimple=(Simple *)KeyValue; cout << "Simple->number: " << pSimple->number << endl; return 1; } void main(void) { Simple *pSimple[imax]; int i; char KeyStr[sizeof(luVOID)+1]; //枚举未销毁的对象用,长度比指针长度大1 if(!InitLu()) return; //初始化Lu LockKey(key_Simple,Del_Simple,OpLock_Simple); //在Lu键树中加锁键,只能存储Simple类型 for(i=0;i
运行结果:Simple: 0
Simple: 1
Simple: 2
Simple: 3
Simple: 4
--- C++ delete 删除约1/2对象 ---
~Simple: 0
~Simple: 1
--- 使用Lu枚举未释放的所有对象 ---
Simple->number: 2
Simple->number: 4
Simple->number: 3
--- Lu系统解锁键并销毁全部对象 ---
~Simple: 2
~Simple: 4
~Simple: 3代码3:效率测试之一,未使用Lu缓冲区
#inc