Making your C++ code robust

  • Introduction

       在實際的項目中,當項目的代碼量不斷增長的時候,你會發現愈來愈難管理和跟蹤其各個組件,如其不善,很容易就引入BUG。所以、咱們應該掌握一些能讓咱們程序更加健壯的方法。數組

       這篇文章提出了一些建議,能有引導咱們寫出更增強壯的代碼,以免產生災難性的錯誤。即便、由於其複雜性和項目團隊結構,你的程序目前不遵循任何編碼規則,按照下面列出的簡單的規則能夠幫助您避免大多數的崩潰狀況。ide

  • Background

        先來介紹下做者開發一些軟件(CrashRpt),你能夠http://code.google.com/p/crashrpt/網站上下載源代碼。CrashRpt 顧名思義軟件崩潰記錄軟件(庫),它可以自動提交你電腦上安裝的軟件錯誤記錄。它經過以太網直接將這些錯誤記錄發送給你,這樣方便你跟蹤軟件問題,並及時修改,使得用戶感受到每次發佈的軟件都有很大的提升,這樣他們天然很高興。函數

圖 一、CrashRpt 庫檢測到錯誤彈出的對話框網站

       在分析接收的錯誤記錄的時候,咱們發現採用下文介紹的方法可以避免大部分程序崩潰的錯誤。例如、局部變量未初始化致使數組訪問越界,指針使用前未進行檢測(NULL)致使訪問訪問非法區域等。google

      我已經總結了幾條代碼設計的方法和規則,在下文一一列出,但願可以幫助你避免犯一些錯誤,使得你的程序更加健壯。編碼

  • Initializing Local Variables 

     使用未初始化的局部變量是引發程序崩潰的一個比較廣泛的緣由,例如、來看下面這段程序片斷:設計

// Define local variables
  BOOL bExitResult; // This will be TRUE if the function exits successfully
  FILE* f; // Handle to file
  TCHAR szBuffer[_MAX_PATH];   // String buffer
    
  // Do something with variables above...

上面的這段代碼存在着一個潛在的錯誤,由於沒有一個局部變量初始化了。當你的代碼運行的時候,這些變量將被默認負一些錯誤的數值。例如bExitResult 數值將被負爲-135913245 ,szBuffer 必須以「\0」結尾,結果不會。所以、局部變量初始化時很是重要的,以下正確代碼:

// Define local variables
  
  // Initialize function exit code with FALSE to indicate failure assumption
  BOOL bExitResult = FALSE; // This will be TRUE if the function exits successfully
  // Initialize file handle with NULL
  FILE* f = NULL; // Handle to file
  // Initialize string buffer with empty string
  TCHAR szBuffer[_MAX_PATH] = _T("");   // String buffer
  // Do something with variables above...

  注意:有人說變量初始化會引發程序效率下降,是的,確實如此,若是你確實很是在意程序的執行效率,去除局部變量初始化,你得想好其後果。指針

  • Initializing WinAPI Structures

       許多Windows API都接受或則返回一些結構體參數,結構體若是沒有正確的初始化,也頗有可能引發程序崩潰。你們可能會想起用ZeroMemory宏或者memset()函數去用0填充這個結構體(對結構體對應的元素設置默認值)。可是大部分Windows API 結構體都必須有一個cbSIze參數,這個參數必須設置爲這個結構體的大小。code

       看看下面代碼,如何初始化Windows API結構體參數:對象

NOTIFYICONDATA nf; // WinAPI structure
  memset(&nf,0,sizeof(NOTIFYICONDATA)); // Zero memory
  nf.cbSize = sizeof(NOTIFYICONDATA); // Set structure size!
  // Initialize other structure members
  nf.hWnd = hWndParent;
  nf.uID = 0;   
  nf.uFlags = NIF_ICON | NIF_TIP;
  nf.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
  _tcscpy_s(nf.szTip, 128, _T("Popup Tip Text"));
        
  // Add a tray icon
  Shell_NotifyIcon(NIM_ADD, &nf);

 注意:千萬不要用ZeroMemory和memset去初始化那些包括結構體對象的結構體,這樣很容易破壞其內部結構體,從而致使程序崩潰.

// Declare a C++ structure
  struct ItemInfo
  {
    std::string sItemName; // The structure has std::string object inside
    int nItemValue;
  }; 
 
  // Init the structure
  ItemInfo item;
  // Do not use memset()! It can corrupt the structure
  // memset(&item, 0, sizeof(ItemInfo));
  // Instead use the following
  item.sItemName = "item1";
  item.nItemValue = 0; 
     這裏最好是用結構體的構造函數對其成員進行初始化.

  // Declare a C++ structure
  struct ItemInfo
  {
    // Use structure constructor to set members with default values
    ItemInfo()
    {
      sItemName = _T("unknown");
      nItemValue = -1;
    }
        
    std::string sItemName; // The structure has std::string object inside
    int nItemValue;
  };
  // Init the structure
  ItemInfo item;
  // Do not use memset()! It can corrupt the structure
  // memset(&item, 0, sizeof(ItemInfo));
  // Instead use the following
  item.sItemName = "item1";
  item.nItemValue = 0;
相關文章
相關標籤/搜索