在釋放一個句柄以前,務必將這個句柄複製僞NULL (0或則其餘默認值)。這樣可以保證程序其餘地方不會重複使用無效句柄。看看以下代碼,如何清除一個Windows API的文件句柄:數組
HANDLE hFile = INVALID_HANDLE_VALUE; // Open file hFile = CreateFile(_T("example.dat"), FILE_READ|FILE_WRITE, FILE_OPEN_EXISTING); if(hFile==INVALID_HANDLE_VALUE) { return FALSE; // Error opening file } // Do something with file // Finally, close the handle if(hFile!=INVALID_HANDLE_VALUE) { CloseHandle(hFile); // Close handle to file hFile = INVALID_HANDLE_VALUE; // Clean up handle }
下面代碼展現如何清除File *句柄:
// First init file handle pointer with NULL FILE* f = NULL; // Open handle to file errno_t err = _tfopen_s(_T("example.dat"), _T("rb")); if(err!=0 || f==NULL) return FALSE; // Error opening file // Do something with file // When finished, close the handle if(f!=NULL) // Check that handle is valid { fclose(f); f = NULL; // Clean up pointer to handle }
若是你分配一個單獨的對象,能夠直接使用new ,一樣你釋放單個對象的時候,能夠直接使用delete . 然而,申請一個對象數組對象的時候可使用new,可是釋放的時候就不能使用delete ,而必須使用delete[]:ide
// Create an array of objects CVehicle* paVehicles = new CVehicle[10]; delete [] paVehicles; // Free pointer to array paVehicles = NULL; // Set pointer with NULL or // Create a buffer of bytes LPBYTE pBuffer = new BYTE[255]; delete [] pBuffer; // Free pointer to array pBuffer = NULL; // Set pointer with NULL
有時候,程序須要動態分配一段緩衝區,這個緩衝區是在程序運行的時候決定的。例如、你須要讀取一個文件的內容,那麼你就須要申請該文件大小的緩衝區來保存該文件的內容。在申請這段內存以前,請注意,malloc() or new是不能申請0字節的內存,如否則,將致使malloc() or new函數調用失敗。傳遞錯誤的參數給malloc() 函數將致使C運行時錯誤。以下代碼展現如何動態申請內存:函數
// Determine what buffer to allocate. UINT uBufferSize = GetBufferSize(); LPBYTE* pBuffer = NULL; // Init pointer to buffer // Allocate a buffer only if buffer size > 0 if(uBufferSize>0) pBuffer = new BYTE[uBufferSize];
爲了進一步瞭解如何正確的分配內存,你能夠讀下Secure Coding Best Practices for Memory Allocation in C and C++這篇文章。post
Asserts用語調試模式檢測先決條件和後置條件。但當咱們編譯器處於release模式的時候,Asserts在預編階段被移除。所以,用Asserts是不可以檢測咱們的程序狀態,錯誤代碼以下:spa
#include <assert.h> // This function reads a sports car's model from a file CVehicle* ReadVehicleModelFromFile(LPCTSTR szFileName) { CVehicle* pVehicle = NULL; // Pointer to vehicle object // Check preconditions assert(szFileName!=NULL); // This will be removed by preprocessor in Release mode! assert(_tcslen(szFileName)!=0); // This will be removed in Release mode! // Open the file FILE* f = _tfopen(szFileName, _T("rt")); // Create new CVehicle object pVehicle = new CVehicle(); // Read vehicle model from file // Check postcondition assert(pVehicle->GetWheelCount()==4); // This will be removed in Release mode! // Return pointer to the vehicle object return pVehicle; }
看看上述的代碼,Asserts可以在debug模式下檢測咱們的程序,在release 模式下卻不能。因此咱們仍是不得不用if()來這步檢測操做。正確的代碼以下;
CVehicle* ReadVehicleModelFromFile(LPCTSTR szFileName, ) { CVehicle* pVehicle = NULL; // Pointer to vehicle object // Check preconditions assert(szFileName!=NULL); // This will be removed by preprocessor in Release mode! assert(_tcslen(szFileName)!=0); // This will be removed in Release mode! if(szFileName==NULL || _tcslen(szFileName)==0) return NULL; // Invalid input parameter // Open the file FILE* f = _tfopen(szFileName, _T("rt")); // Create new CVehicle object pVehicle = new CVehicle(); // Read vehicle model from file // Check postcondition assert(pVehicle->GetWheelCount()==4); // This will be removed in Release mode! if(pVehicle->GetWheelCount()!=4) { // Oops... an invalid wheel count was encountered! delete pVehicle; pVehicle = NULL; } // Return pointer to the vehicle object return pVehicle; }
判定一個函數執行必定成功是一種常見的錯誤。當你調用一個函數的時候,建議檢查下返回代碼和返回參數的值。以下代碼持續調用Windows API ,程序是否繼續執行下去依賴於該函數的返回結果和返回參數值。debug
HRESULT hres = E_FAIL; IWbemServices *pSvc = NULL; IWbemLocator *pLoc = NULL; hres = CoInitializeSecurity( NULL, -1, // COM authentication NULL, // Authentication services NULL, // Reserved RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation NULL, // Authentication info EOAC_NONE, // Additional capabilities NULL // Reserved ); if (FAILED(hres)) { // Failed to initialize security if(hres!=RPC_E_TOO_LATE) return FALSE; } hres = CoCreateInstance( CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc); if (FAILED(hres) || !pLoc) { // Failed to create IWbemLocator object. return FALSE; } hres = pLoc->ConnectServer( _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace NULL, // User name. NULL = current user NULL, // User password. NULL = current 0, // Locale. NULL indicates current NULL, // Security flags. 0, // Authority (e.g. Kerberos) 0, // Context object &pSvc // pointer to IWbemServices proxy ); if (FAILED(hres) || !pSvc) { // Couldn't conect server if(pLoc) pLoc->Release(); return FALSE; } hres = CoSetProxyBlanket( pSvc, // Indicates the proxy to set RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx NULL, // Server principal name RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx NULL, // client identity EOAC_NONE // proxy capabilities ); if (FAILED(hres)) { // Could not set proxy blanket. if(pSvc) pSvc->Release(); if(pLoc) pLoc->Release(); return FALSE; }