1. 程式人生 > >[C/C++]_[中級]_[使用智慧指標的方式釋放malloc出來的堆空間]

[C/C++]_[中級]_[使用智慧指標的方式釋放malloc出來的堆空間]

場景:

1. 使用auto_ptr 的方式可以wrap類物件,  之後在方法結束後可以自動釋放物件, 參考;這樣在有條件判斷的語句時可以省掉free語句或CloseHandle.

2.C++的特性之一就是類物件(非返回值的物件)在方法結束後會自動呼叫解構函式,這樣在解構函式裡可以放一些釋放資源的操作.

3. 這裡實現了一個類似auto_ptr的類的實用Wrap類,可以參考根據自己需要自定義特定的Wrap類.auto_ptr的壞處之一就是隻支援new出來的物件,

之二是不能刪除陣列. delete []

4. 恰當使用WrapObject能有效的減少記憶體洩漏,因為在很多C程式設計裡, 太多的if語句在return前需要釋放物件,很容易就會出錯或多次釋放。

檔案 wrap_object.h

#ifndef __WRAP_OBJECT
#define __WRAP_OBJECT

#include <stdlib.h>
#include <Windows.h>


template<BOOL (WINAPI* WrapHandleFunc)(void*)>
class WrapHandle
{
public:
	WrapHandle(void* data):data_(data){}
	~WrapHandle()
	{
		if(data_)
		{
			WrapHandleFunc(data_);
			data_ = NULL;
		}
	}
private:
	void* data_;
};

class WrapMalloc
{
public:
	WrapMalloc(void* data):data_(data){}

	~WrapMalloc()
	{ 
		free(data_);
		data_ = NULL;
	}
	void Reset()
	{
		free(data_);
		data_ = NULL;
	}
private:
	void* data_;
};

#endif

使用方式:
// Specify an HTTP server.
  const char* www = "www";
  std::string URLADDR = DhOptionDomain::GetValue("url:brand");
  const char* www_start = strstr(URLADDR.c_str(),www);
  

  if( !hSession )
  {
	  return kNetworkError;
  }
  WrapHandle<WinHttpCloseHandle> session_wh(hSession);
  
  wchar_t* www_start_unicode = ConvertUtf8ToUnicode(www_start);
  WrapMalloc www_wm(www_start_unicode);
  hConnect = WinHttpConnect( hSession, www_start_unicode,  
                               INTERNET_DEFAULT_HTTP_PORT, 0 ); 

  // Create an HTTP request handle.  
  if(!hConnect )  
  {
	 return kNetworkError;  
  }
  WrapHandle<WinHttpCloseHandle> connect_wh(hConnect);

  hRequest = WinHttpOpenRequest( hConnect, L"GET", L"/win-update.xml",  
                                   NULL, WINHTTP_NO_REFERER,   
                                   WINHTTP_DEFAULT_ACCEPT_TYPES,   
                                   WINHTTP_FLAG_REFRESH ); 
  // Send a request.  
  if(!hRequest)
  {
	 return kNetworkError;
  } 

  WrapHandle<WinHttpCloseHandle> request_wh(hRequest);

  bResults = WinHttpSendRequest( hRequest,  
                                   WINHTTP_NO_ADDITIONAL_HEADERS, 0,  
                                   WINHTTP_NO_REQUEST_DATA, 0,   
                                   0, 0 );
  
  // End the request.  
  if(!bResults )
  {
	return kNetworkError;
  } 
  bResults = WinHttpReceiveResponse( hRequest, NULL );  

注意: 如果沒有WrapObject的話你就得記得在if裡釋放不斷增加的 Handle物件,它是提高程式質量的好處之一,建議直接用到專案裡.