VC++自释放指针、自释放虚拟内存、自关闭句柄、局部作用域回调函数调用等辅助开发类

#pragma once

#ifndef NULL
#define NULL 0
#endif

namespace RangeHelper
{
	template <class T>
	class CAutoDeletePtr {
		//自动删除指针
	public:
		CAutoDeletePtr() : m_ptr(NULL) {

		}

		CAutoDeletePtr(T* ptr) {
			m_ptr = ptr;
		}

		~CAutoDeletePtr() {
			Free();
		}

		void Free() {
			if (!m_ptr) return;

			delete []m_ptr;
			m_ptr = NULL;
		}

		bool Allocate(size_t nElements) {
			Free();

			m_ptr = new T[nElements];
			if (!m_ptr) return false;

			return true;
		}

		void Attach(T* p) {
			ASSERT(p != NULL);

			m_ptr = p;
		}

		T* Detach() {
			T* p;

			p = m_p;
			m_p = NULL;

			return( p );
		}

		T operator[](int i) const
		{
			ASSERT((i>=0) && AfxIsValidAddress(m_ptr, sizeof(T)*i));
			return m_ptr[i];
		}

		T& operator[](int i)
		{
			ASSERT((i>=0) && AfxIsValidAddress(m_ptr, sizeof(T)*i));
			return m_ptr[i];
		}

		CAutoDeletePtr<T>& operator=(const T* ptr)
		{
			if ((m_ptr != NULL) && (m_ptr != ptr))
			{
				if (m_ptr != NULL)
				{
					delete []m_ptr;
					m_ptr = NULL;
				}
			}

			m_ptr = const_cast<T*>(ptr);

			return *this;
		}

		operator T*() const
		{
			return m_ptr;
		}

	private:
		T *m_ptr;
	};

	template <class T>
	class CAutoReleaseVM
		//自释放虚拟内存
	{
	public:
		CAutoReleaseVM() :m_ptr(NULL), m_nCnt(0) {

		}

		CAutoReleaseVM(T* vmData, ULONG nCnt) {
			ASSERT(vmData);
			ASSERT(nCnt>0);
			m_ptr	= vmData;
			m_nCnt	= nCnt;
		}

		CAutoReleaseVM(ULONG nElementCnt, DWORD flAllocationType=MEM_COMMIT, DWORD flProtect=PAGE_READWRITE) : m_ptr(NULL) {
			AllocateVM(nElementCnt, flAllocationType, flProtect);
		}

		~CAutoReleaseVM()
		{
			FreeVM();
		}

		void FreeVM()
		{
			if (m_ptr) {
				VirtualFree(m_ptr, 0, MEM_RELEASE);
				m_nCnt	= 0;
				m_ptr	= NULL;
			}
		}

		BOOL AllocateVM(ULONG nElementCnt, DWORD flAllocationType=MEM_COMMIT, DWORD flProtect=PAGE_READWRITE)
		{
			FreeVM();
			m_ptr	= (T*)VirtualAlloc(NULL, nElementCnt*sizeof(T), flAllocationType, flProtect);
			m_nCnt	= nElementCnt;
			return (m_ptr!=NULL);
		}

		BOOL ReAllocateVM(ULONG nElementCnt, BOOL bCopyOld=TRUE, DWORD flAllocationType=MEM_COMMIT, DWORD flProtect=PAGE_READWRITE)
		{
			if (!bCopyOld)
				return AllocateVM(nElementCnt, flAllocationType, flProtect);

			T *tmp = (T*)VirtualAlloc(NULL, nElementCnt*sizeof(T), flAllocationType, flProtect);
			if (!tmp)
				return FALSE;

			memmove(tmp, m_ptr, min(nElementCnt, m_nCnt)*sizeof(T));
			m_ptr = tmp;
			m_nCnt= nElementCnt;
			return TRUE;
		}

		BOOL IsOK() {
			return (m_ptr!=NULL);
		}

		size_t GetDataBytes() {
			size_t nDataBytes = 0;
			if (IsOK()) {
				nDataBytes = GetTypeSize()*m_nCnt;
			}
			return nDataBytes;
		}

		size_t GetTypeSize() {
			return sizeof(T);
		}

		ULONG GetDataCount() {
			ULONG nDataCount = 0;
			if (IsOK()) {
				nDataCount = m_nCnt;
			}
			return nDataCount;
		}

		T operator[](size_t i) const
		{
			ASSERT((i>=0) && m_ptr && AfxIsValidAddress(m_ptr, sizeof(T)*i));
			return m_ptr[i];
		}

		T& operator[](size_t i)
		{
			ASSERT((i>=0) && m_ptr && AfxIsValidAddress(m_ptr, sizeof(T)*i));
			return m_ptr[i];
		}

		operator T*() const
		{
			return m_ptr;
		}

	private:
		T*		m_ptr;
		size_t	m_nCnt;
	};

	class CAutoCloseHandle
		//自动关闭句柄类
	{
	public:
		CAutoCloseHandle(HANDLE* handle=NULL) : m_handle(handle)
		{
		}		

		CAutoCloseHandle& operator=(HANDLE* rh)
		{
			if (m_handle) {
				CloseHandle(m_handle);
				m_handle = NULL;
			}
			m_handle = rh;

			return *this;
		}

		~CAutoCloseHandle()
		{
			CloseHandle(*m_handle);
		}

	private:
		HANDLE *m_handle;
	};

	template <class T>
	class CAutoDeleteArray : public CArray<T*, T*>
	{
	public:
		~CAutoDeleteArray() {
			RemoveAll();
		}

		void RemoveAt(INT_PTR nIndex, INT_PTR nCount = 1)
		{
			ASSERT(nCount>0);
			for (INT_PTR i=nIndex; i!=min(nIndex+nCount, GetCount()); ++i)
			{
				T *pItem = GetAt(i);
				delete pItem;
			}
			CArray::RemoveAt(nIndex, nCount);
		}

		void RemoveAll()
		{
			for (INT_PTR i=0; i!=GetCount(); ++i)
			{
				T *pItem = GetAt(i);
				delete pItem;
			}
			CArray::RemoveAll();
		}
	};

/*
	//CRangeFxnHelper使用示例
	class A
	{
	public:
		void func1(){
			cout << 1 << endl;
		}

		void func2(){
			cout << 2 << endl;
		}

		void test()	{
			CRangeFxnHelper<A> a(this, &A::func1, &A::func2);
		}
	};
*/
	template <class T>
	class CRangeFxnHelper
	//局部函数调用
	{
		typedef void(T::* MemFxnPtr)(void); //成员函数
	public:
		CRangeFxnHelper(T* pClassName,
			MemFxnPtr lpfxnEnter,
			MemFxnPtr lpfxnLeave = NULL) : m_pClassName(pClassName),
			m_lpfxnLeave(lpfxnLeave)
		{
			ASSERT(pClassName != NULL);
			ASSERT(lpfxnEnter != NULL);

			(m_pClassName->*lpfxnEnter)();
		}

		~CRangeFxnHelper()
		{
			if (m_lpfxnLeave != NULL)
				(m_pClassName->*m_lpfxnLeave)();
		}

	private:
		T *m_pClassName;
		MemFxnPtr m_lpfxnLeave;
	};

	template <class T>
	class CAutoRevertBOOL
	//自动反置布尔变量
	{
	public:
		CAutoRevertBOOL(T *pObjBool, T initVal) : m_pObjBool(pObjBool),
			m_InitVal(initVal)
		{
			ASSERT(pObjBool != NULL);

			*pObjBool = initVal;
		}

		~CAutoRevertBOOL()
		{
			*m_pObjBool = !m_InitVal;
		}

	private:
		T *m_pObjBool;
		T m_InitVal;
	};

	class CAutoDisableEnableChildCtls
	{
	public:
		CAutoDisableEnableChildCtls(HWND hwndParent, UINT nFirstExcludeChildCtrlID=-1, ...)
			: m_hwndParent(hwndParent), m_bDisabled(FALSE)
		{
			AddExcludeCtrlIDs(nFirstExcludeChildCtrlID);
		}

		~CAutoDisableEnableChildCtls()
		{
			if (m_bDisabled)
				SwitchStatus();
		}

		void SwitchStatus()
		{
			struct stEnumChild
			{
				BOOL				*pChangeStatus		;//改变状态
				CArray<UINT, UINT>	*pArrayExcludeID	;//无须进行状态改变的列表
				CArray<HWND, HWND>	*pStatusChangedWND	;//已经改变的窗口
			};

			class CEnumChildHelper
			{
			public:
				static BOOL __stdcall EnumChildProc(HWND hwnd, LPARAM lParam)
				{
					stEnumChild *pParam		= (stEnumChild *)lParam;
					LONG lStyle				= GetWindowLong(hwnd, GWL_STYLE);
					BOOL bDisable			= *(pParam->pChangeStatus);
					CArray<UINT, UINT> &arr = *(pParam->pArrayExcludeID);
					CArray<HWND, HWND> &aChanged = *(pParam->pStatusChangedWND);

					for (int i=0; i!=arr.GetCount(); ++i)
					{
						if (GetDlgCtrlID(hwnd) == arr[i]) return TRUE;
					}

					TCHAR szClsName[512] = {_T('\0')};
					GetClassName(hwnd, szClsName, 512);
					if (!_tcscmp(szClsName, _T("Internet Explorer_Server")))//不处理Web浏览器
						return TRUE;
					if (!_tcscmp(szClsName, _T("Static"))) //静态文本
						return TRUE;

					if (bDisable)
					{
						if ((lStyle&WS_DISABLED) != WS_DISABLED) {
							lStyle |= WS_DISABLED;
							aChanged.Add(hwnd);
						}
					} else {
						if ((lStyle&WS_DISABLED) == WS_DISABLED) {
							int i = 0;
							for (; i!=aChanged.GetCount(); ++i)
							{
								if (hwnd == aChanged[i])
									break;
							}
							if (i == aChanged.GetCount()) {
								//未在已处理过的控件列表中
								return TRUE;
							}
							aChanged.RemoveAt(i);

							lStyle &= ~WS_DISABLED;
						}
					}

					SetWindowLong(hwnd, GWL_STYLE, lStyle);
					::InvalidateRect(hwnd, NULL, TRUE);
					return TRUE;
				}
			};

			stEnumChild param;
			param.pChangeStatus		= &m_bDisabled;
			param.pArrayExcludeID	= &m_aExcludeIDs;
			param.pStatusChangedWND = &m_aStatusChangedChild;

			m_bDisabled = !m_bDisabled;

			EnumChildWindows(m_hwndParent, CEnumChildHelper::EnumChildProc, (LPARAM)¶m);
		}

		void AddExcludeCtrlIDs(UINT nID, ...)
			//以-1结尾
		{
			va_list arglst;
			va_start(arglst, nID);

			while (nID != (UINT)-1)
			{
				//防止添加多次
				for (INT_PTR i=0; i!=m_aExcludeIDs.GetSize(); ++i)
				{
					if (nID == m_aExcludeIDs[i]) goto Next;
				}
				m_aExcludeIDs.Add(nID);
Next:
				nID = va_arg(arglst, UINT);
			}
			va_end(arglst);
		}

	private:
		HWND				m_hwndParent;
		CArray<UINT, UINT>  m_aExcludeIDs;
		BOOL				m_bDisabled;
		CArray<HWND, HWND>	m_aStatusChangedChild;
	};

	class CAutoWndStatusSwitch
		//自动转换窗口使能与禁用状态
	{
	public:
		//ID 以-1结尾
		CAutoWndStatusSwitch(HWND hwndParent, UINT nID=-1, ...)
			: m_hwndParent(hwndParent), m_bSwitched(FALSE)
		{
			ASSERT(hwndParent != NULL);

			AddCtrls(nID);
		}
		~CAutoWndStatusSwitch()
		{
			if (m_bSwitched)
				SwitchStatus();
		}

		void AddCtrls(UINT nID, ...)
			//以-1结尾
		{
			va_list arglst;
			va_start(arglst, nID);

			while (nID != (UINT)-1)
			{
				//防止添加多次
				for (INT_PTR i=0; i!=m_aIDs.GetSize(); ++i)
				{
					if (nID == m_aIDs[i]) goto Next;
				}
				m_aIDs.Add(nID);
Next:
				nID = va_arg(arglst, UINT);
			}
			va_end(arglst);
		}

		void SwitchStatus()
			//状态转换
		{
			m_bSwitched = !m_bSwitched;
			for (INT_PTR i=0; i!=m_aIDs.GetSize(); ++i)
			{
				HWND hCtrl = GetDlgItem(m_hwndParent, m_aIDs[i]);
				if (!IsWindow(hCtrl)) continue;

				LONG lStyle = GetWindowLong(hCtrl, GWL_STYLE);

				if ((lStyle&WS_DISABLED) == WS_DISABLED)
					lStyle &= ~WS_DISABLED;
				else
					lStyle |= WS_DISABLED;

				SetWindowLong(hCtrl, GWL_STYLE, lStyle);
				::InvalidateRect(hCtrl, NULL, TRUE);
			}
		}
	private:
		HWND				m_hwndParent;
		CArray<UINT, UINT>  m_aIDs;
		BOOL				m_bSwitched;
	};

	class CAutoHideShowWnd
		//自动隐藏窗口
	{
	public:
		CAutoHideShowWnd(HWND hWnd, BOOL bHide=TRUE):m_hWnd(hWnd)
		{
			ASSERT(IsWindow(hWnd));
			if (bHide) Hide();
		}

		~CAutoHideShowWnd()
		{
			Restore();
		}

		void Hide()
		{
			if (IsWindow(m_hWnd) &&
				(GetWindowLong(m_hWnd, GWL_STYLE) & WS_VISIBLE)) {
					ShowWindow(m_hWnd, SW_HIDE);
			}
		}

		void Restore()
		{
			if (IsWindow(m_hWnd) &&
				(GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_VISIBLE)) {
					ShowWindow(m_hWnd, SW_SHOW);
			}
		}

	private:
		HWND m_hWnd;
	};
}

时间: 2025-01-04 15:13:27

VC++自释放指针、自释放虚拟内存、自关闭句柄、局部作用域回调函数调用等辅助开发类的相关文章

QList 列表指针的 释放

1,使用qDeleteAll() QList<T*> list: qDeleteAll(list): list = NULL; QList<T*> *listp: qDeleteAll(*list): listp.clear(); listp = NULL; 2.通过遍历列表对列表一个一个的释放. 在释放指针的同时把值清空,赋值为BULL 避免野指针. QList<T *> *qList = new QList<T *>  动态分配内存空间 不使用时需要释放

C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针

(1)开辟的内存没有释放,造成内存泄露 (2)野指针被使用或释放 (3)非法释放指针 (1)开辟的内存没有释放,造成内存泄露,下面的例子就可能造成20个字节的泄露,内存泄露不是一个立即会引发故障的错误,但是 它将消耗系统内存. void function1() { char *pa; pa = (char*)malloc(sizeof(char)*20); if(NULL !=pa) { strcpy(pa,"hello"); printf("pa = %x\n",

Linux 快速释放端口与释放内存缓存

在Linux系统中做系统测试有时会遇到端口占用过多来不及释放,导致应用错误的情况,使用如下的命令即能让端口被快速回收.但需要注意的是,打开tcp_tw_reccycle,kernel会检查对端机器的包的时间戳,所以生产上是否打开tcp_tw_reccycle,还需根据应用而看. sysctl -w net.ipv4.tcp_tw_recycle=1 在测试块设备性能时,有些数据会被缓存至内存中,导致测试结果虚大,使用如下命令可以清空内存缓存 sysctl -w vm.drop_caches=3

FreeOnTerminate 的线程在线程管理类的Destroy释放时手工释放的问题

这个问题折腾了我整整一天. 有一个线程管理类,集中管理所有新建的线程, 线程统一在创建时标识 FreeOnTerminate 为 True. 因为有的线程是不限次循环的,所以在管理类最后 Destroy 时必须对这些线程进行手工停止并释放. 开始代码: FAllThread.Items[i].FOwner := nil; //释放时不必再消息通知管理类删除记录 FAllThread.Items[i].Terminate; 发现 FastMM检测有内存泄露,想了下因为线程还没结束,但主进程结束了,

利用Js/Jquery实现div的隐藏与显示(注意释放与不释放空间)

JS隐藏和显示div的方式有两种:方式1:隐藏后释放占用的页面空间通过设置display属性可以使div隐藏后释放占用的页面空间. style="display: none;" document.getElementById("demo").style.display="none";//隐藏 document.getElementById("demo").style.display="";//显示 方式2:

C语言中的回调函数调用过程以及函数指针使用

回调函数比喻: 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货. 在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件. 回调函数是一个程序员不能显式调用的函数:通过将回调函数的地址传给调用者从而实现调用. 回调函数使用是必要的,在我们想通过一个统一接口实现不同的内容,这时用

一个常见的错误时编写代码

实验室阶段做练习,其中,变化bug称号: #include <iostream> #include <vector> int main(int, char**) { std::vector<int>** ppRandomData = distributeRandomInt(100); for (unsigned int i=0; i<1000; i++) { if (ppRandomData[i]) { std::cout << "Eleme

【C++ Primer】特殊工具与技术

十七.用于大型程序的工具 1. 优化内存分配 C++类型分配是一个类型化操作:new为特定类型分配内存,并在新分配的内存中构造对象.new表达式会为每个动态分配的类自动调用构造函数.但有些时候需要将内存分配与对象构造分开,因为对预先分配,但以后却不使用的对象进行构造很是浪费的. C++提供两种方法,分配和释放未构造的的原始内存: 1:allocator类,它提供可感知类型的内存分配.这个类使用allocate成员分配内存,使用deallocate成员释放内存. 2:标准库中的operator n

节省创建对象数组的技巧

... 不管Student obj[10];//obj是指针首地址 还是Student* pStudent=new Student[10];...delete  pStudent; ... 实际上最终给各个对象初始化的时候调用的都是默认的构造函数(结构体是没有构造函数的),如果有重载的构造函数的话,再使用这种方式岂不浪费时间?以下是解决方法:class Student {public:     Student();     Student(char name[20],int age,float