C/C++使用Lu键树实现智能指针及检查内存泄露

欢迎访问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 <windows.h>
#include <iostream>
#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<imax;i++)
	{
		pSimple[i]=new Simple(i);
	}

	cout << endl << "--- C++ delete 删除约1/2对象 ---" << endl << endl;
	for(i=0;i<imax/2;i++)
	{
		delete pSimple[i];
	}

	cout << endl << "--- Lu系统解锁键并销毁全部对象 ---" << endl << endl;
	LockKey(key_Simple,NULL,OpLock_Simple);	//在Lu键树中解锁键

	FreeLu();		//释放Lu
}


运行结果:

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 <iostream>
#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 GetKeySimpleValue(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<imax;i++)
	{
		pSimple[i]=new Simple(i);
	}

	cout << endl << "--- C++ delete 删除约1/2对象 ---" << endl << endl;
	for(i=0;i<imax/2;i++)
	{
		delete pSimple[i];
	}

	cout << endl << "--- 使用Lu枚举未释放的所有对象 ---" << endl << endl;
	EnumKey(key_Simple,KeyStr,sizeof(luVOID)+1,GetKeySimpleValue);

	cout << endl << "--- Lu系统解锁键并销毁全部对象 ---" << endl << endl;
	LockKey(key_Simple,NULL,OpLock_Simple);		//在Lu键树中解锁键

	FreeLu();			//释放Lu
}


运行结果:

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缓冲区

#include <windows.h>
#include <iostream>
#include <time.h>
#include "lu32.h"

#pragma comment( lib, "lu32.lib" )

using namespace std;

#define key_Simple		(luPriKey_User-20)	//将对该私有键加锁

#define imax		10	//私有键值最大数,修改此数据时要同时修改下面的循环次数kmax
int kmax = 100000;			//循环次数

void _stdcall Del_Simple(void *me);		//销毁Simple的函数

class Simple		//编写一个简单的类帮助测试:使用Lu系统
{
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;
	};

	~Simple()
	{
		//在类的初始化函数中增加以下几行代码
		void *me;
		if(!bDelete)	//如果用户手动delete
		{
			bDelete=true;
			me=this;
			DeleteKey((char *)&(me),sizeof(luVOID),key_Simple,Del_Simple,0);	//在Lu键树中删除键值
		}

		//销毁对象的其他代码
	};
};
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;
}

class SimpleCpp		//编写一个简单的类帮助测试:不使用Lu系统
{
public:
	int number;	//数据

	SimpleCpp(int param=0)
	{
		//初始化代码
		number = param;
	};

	~SimpleCpp()
	{
		//销毁对象的其他代码
	};
};

void main(void)
{
	Simple *pSimple[imax];
	SimpleCpp *pSimpleCpp[imax];
	int i,j;
	clock_t start, end;

	start = clock();
	for(j=0;j<kmax;j++)
	{
		for(i=0;i<imax;i++)
		{
			pSimpleCpp[i]=new SimpleCpp(i);
		}
		for(i=0;i<imax;i++)
		{
			delete pSimpleCpp[i];
		}
	}
	end = clock();
	cout << "--- C/C++ 系统运行时间 : " << end - start << " ms." << endl;

	

	if(!InitLu()) return;	//初始化Lu

	LockKey(key_Simple,Del_Simple,OpLock_Simple);	//在Lu键树中加锁键,只能存储Simple类型

	start = clock();
	for(j=0;j<kmax;j++)
	{
		for(i=0;i<imax;i++)
		{
			pSimple[i]=new Simple(i);
		}
		for(i=0;i<imax;i++)
		{
			delete pSimple[i];
		}
	}
	end = clock();
	cout << "--- C/C++ Lu 复合系统运行时间 : " << end - start << " ms." << endl;

	LockKey(key_Simple,NULL,OpLock_Simple);	//在Lu键树中解锁键

	FreeLu();		//释放Lu
}


运行结果:

--- C/C++ 系统运行时间 : 218 ms.
--- C/C++ Lu 复合系统运行时间 : 10578 ms.

代码4:效率测试之二,使用Lu缓冲区

#include <windows.h>
#include <iostream>
#include <time.h>
#include "lu32.h"

#pragma comment( lib, "lu32.lib" )

using namespace std;

#define key_Simple		(luPriKey_User-20)	//将对该私有键加锁

#define imax		10	//私有键值最大数,修改此数据时要同时修改下面的循环次数kmax
int kmax = 100000;			//循环次数

void _stdcall Del_Simple(void *me);		//销毁Simple的函数

class Simple		//编写一个简单的类帮助测试:使用Lu系统
{
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;
	};

	~Simple()
	{
		//在类的初始化函数中增加以下几行代码
		void *me;
		if(!bDelete)	//如果用户手动delete
		{
			bDelete=true;
			me=this;
			DeleteKey((char *)&(me),sizeof(luVOID),key_Simple,Del_Simple,0);	//在Lu键树中删除键值
		}

		//销毁对象的其他代码
	};
};
Simple *NewSimple(int param=0)	//设计专用的生成Simple的函数
{
	Simple *pSimple;
	char keyname[sizeof(luVOID)];

	pSimple=(Simple *)GetBufObj(key_Simple,keyname);	//先尝试从缓冲区中获取一个Simple对象
	if(pSimple)		//获得对象后初始化
	{
		pSimple->number=param;
	}
	else			//生成新的对象并初始化
	{
		pSimple=new Simple(param);
	}
	return pSimple;
}
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;
}

class SimpleCpp		//编写一个简单的类帮助测试:不使用Lu系统
{
public:
	int number;	//数据

	SimpleCpp(int param=0)
	{
		//初始化代码
		number = param;
	};

	~SimpleCpp()
	{
		//销毁对象的其他代码
	};
};

void main(void)
{
	Simple *pSimple[imax];
	SimpleCpp *pSimpleCpp[imax];
	int i,j;
	clock_t start, end;

	start = clock();
	for(j=0;j<kmax;j++)
	{
		for(i=0;i<imax;i++)
		{
			pSimpleCpp[i]=new SimpleCpp(i);
		}
		for(i=0;i<imax;i++)
		{
			delete pSimpleCpp[i];
		}
	}
	end = clock();
	cout << "--- C/C++ 系统运行时间 : " << end - start << " ms." << endl;

	

	if(!InitLu()) return;	//初始化Lu

	LockKey(key_Simple,Del_Simple,OpLock_Simple);	//在Lu键树中加锁键,只能存储Simple类型

	start = clock();
	for(j=0;j<kmax;j++)
	{
		for(i=0;i<imax;i++)
		{
			pSimple[i]=NewSimple(i);	//使用专用的生成Simple的函数
		}
		for(i=0;i<imax;i++)
		{
			//delete pSimple[i];
			//通过在Lu键树中删除键值的方法销毁对象,参数1表示先将对象放入缓冲池,由Lu系统择机销毁
			DeleteKey((char *)&(pSimple[i]),sizeof(luVOID),key_Simple,Del_Simple,1);
		}
	}
	end = clock();
	cout << "--- C/C++ Lu 复合系统运行时间 : " << end - start << " ms." << endl;

	LockKey(key_Simple,NULL,OpLock_Simple);	//在Lu键树中解锁键

	FreeLu();		//释放Lu
}


运行结果:

--- C/C++ 系统运行时间 : 234 ms.
--- C/C++ Lu 复合系统运行时间 : 125 ms.

4函数说明

    本例用到了Lu的7个输出函数:初始化Lu的函数InitLu,释放Lu的函数FreeLu,插入键值的函数InsertKey删除键值的函数DeleteKey,加锁键函数LockKey,枚举键值的函数EnumKey,从缓冲池中获取一个对象的函数GetBufObj。从这里查看这些函数的说明:Lu编程指南

5 难点分析

    代码1实现了智能指针。对C/C++程序来说,仅需要在类的构造函数和析构函数中添加几行代码;当然,加载Lu核心库、对指定的数据类型进行加锁和解锁还是必不可少的。

    代码2在代码1的基础上实现了对C/C++程序内存泄露的检查。仅增加了一个枚举键值的函数EnumKey

    代码3对使用Lu智能指针的对象生成及销毁效率进行了测试,并与C/C++做了比较,结果表明:在不使用Lu缓冲池时,C/C++和Lu复合程序的效率约为C/C++程序的1/50左右。

    代码4仍然对使用Lu智能指针的对象生成及销毁效率进行测试,但使用Lu缓冲池,结果表明:在使用Lu缓冲池时,C/C++和Lu复合程序的效率接近C/C++程序的2倍。使用Lu缓冲池需要付出的代价是,你必须专门设计一个生成对象的函数来代替new操作符,销毁对象时也不要直接delete,而要使用Lu系统的函数DeleteKey。另外,代码4在小范围内进行了对象的生成及销毁的测试(对象数目 imax=10),充分利用了Lu缓冲池,这是符合一般程序运行情况的;如果修改代码4中的 imax=1000kmax=1000(循环次数)再进行测试,将会发现,C/C++和Lu复合程序的效率将退化为代码3的情况。

6 其他

    你可能注意到了,我的联系方式就在下面,如有不明之处或有什么建议,可随时与我进行联系。


版权所有© Lu程序设计 2002-2013,保留所有权利
E-mail: forcal@sina.com
  QQ:630715621
最近更新: 2014年01月03日

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值