Making your C++ code robust

  • Cleaning Up Released Handles 

      在釋放一個句柄以前,務必將這個句柄複製僞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
  }

  • Using delete [] Operator for Arrays 

     若是你分配一個單獨的對象,能夠直接使用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

  • Allocating Memory Carefully 

     有時候,程序須要動態分配一段緩衝區,這個緩衝區是在程序運行的時候決定的。例如、你須要讀取一個文件的內容,那麼你就須要申請該文件大小的緩衝區來保存該文件的內容。在申請這段內存以前,請注意,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

  • Using Asserts Carefully

       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;
  }

  • Checking Return Code of a Function 

        判定一個函數執行必定成功是一種常見的錯誤。當你調用一個函數的時候,建議檢查下返回代碼和返回參數的值。以下代碼持續調用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;               
    }
相關文章
相關標籤/搜索