C++內存管理詳解

踏入C++中的雷區——C++內存管理詳解

      這篇文章回答了我之前的一個問題,就是分配內存用malloc好,還是用new好,今天跑程序的時候,發現malloc老是失敗,氣得不行,最後看到了這篇文章,原來如此,以後堅決用new了。。。。

       1、有了malloc/free爲什麼還要new/delete?

  malloc與free是C++/C語言的標準庫函數,new/delete是C++的運算符。它們都可用於申請動態內存和釋放內存。

  對於非內部數據類型的對象而言,光用maloc/free無法滿足動態對象的要求。對象在創建的同時要自動執行構造函數,對象在消亡之前要自動執行析構函數。由於malloc/free是庫函數而不是運算符,不在編譯器控制權限之內,不能夠把執行構造函數和析構函數的任務強加於malloc/free。

   因此C++語言需要一個能完成動態內存分配和初始化工作的運算符new,以及一個能完成清理與釋放內存工作的運算符delete。注意new/delete不是庫函數。我們先看一看malloc/free和new/delete如何實現對象的動態內存管理,見示例6。

class Obj
{
 public :
  Obj(void){ cout << “Initialization” << endl; }
  ~Obj(void){ cout << “Destroy” << endl; }
  void Initialize(void){ cout << “Initialization” << endl; }
  void Destroy(void){ cout << “Destroy” << endl; }
};
void UseMallocFree(void)
{
 Obj *a = (obj *)malloc(sizeof(obj)); // 申請動態內存
 a->Initialize(); // 初始化
 //…
 a->Destroy(); // 清除工作
 free(a); // 釋放內存
}
void UseNewDelete(void)
{
 Obj *a = new Obj; // 申請動態內存並且初始化
 //…
 delete a; // 清除並且釋放內存
}
     示例6 用malloc/free和new/delete如何實現對象的動態內存管理

 

  類Obj的函數Initialize模擬了構造函數的功能,函數Destroy模擬了析構函數的功能。函數UseMallocFree中,由於malloc/free不能執行構造函數與析構函數,必須調用成員函數Initialize和Destroy來完成初始化與清除工作。函數UseNewDelete則簡單得多。

  所以我們不要企圖用malloc/free來完成動態對象的內存管理,應該用new/delete。由於內部數據類型的“對象”沒有構造與析構的過程,對它們而言malloc/free和new/delete是等價的。

  既然new/delete的功能完全覆蓋了malloc/free,爲什麼C++不把malloc/free淘汰出局呢?這是因爲C++程序經常要調用C函數,而C程序只能用malloc/free管理動態內存。

  如果用free釋放“new創建的動態對象”,那麼該對象因無法執行析構函數而可能導致程序出錯。如果用delete釋放“malloc申請的動態內存”,理論上講程序不會出錯,但是該程序的可讀性很差。所以new/delete必須配對使用,malloc/free也一樣。

  2、內存耗盡怎麼辦?

  如果在申請動態內存時找不到足夠大的內存塊,malloc和new將返回NULL指針,宣告內存申請失敗。通常有三種方式處理“內存耗盡”問題。

  (1)判斷指針是否爲NULL,如果是則馬上用return語句終止本函數。例如:

void Func(void)
{
 A *a = new A;
 if(a == NULL)
 {
  return;
 }
 …
}

  (2)判斷指針是否爲NULL,如果是則馬上用exit(1)終止整個程序的運行。例如:

void Func(void)
{
 A *a = new A;
 if(a == NULL)
 {
  cout << “Memory Exhausted” << endl;
  exit(1);
 }
 …
}

  (3)爲new和malloc設置異常處理函數。例如Visual C++可以用_set_new_hander函數爲new設置用戶自己定義的異常處理函數,也可以讓malloc享用與new相同的異常處理函數。詳細內容請參考C++使用手冊。

  上述(1)(2)方式使用最普遍。如果一個函數內有多處需要申請動態內存,那麼方式(1)就顯得力不從心(釋放內存很麻煩),應該用方式(2)來處理。

  很多人不忍心用exit(1),問:“不編寫出錯處理程序,讓操作系統自己解決行不行?”

  不行。如果發生“內存耗盡”這樣的事情,一般說來應用程序已經無藥可救。如果不用exit(1) 把壞程序殺死,它可能會害死操作系統。道理如同:如果不把歹徒擊斃,歹徒在老死之前會犯下更多的罪。

  有一個很重要的現象要告訴大家。對於32位以上的應用程序而言,無論怎樣使用malloc與new,幾乎不可能

 

導致“內存耗盡”。我在Windows 98下用Visual C++編寫了測試程序,見示例7。這個程序會無休止地運行下去,根本不會終止。因爲32位操作系統支持“虛存”,內存用完了,自動用硬盤空間頂替。我只聽到硬盤嘎吱嘎吱地響,Window 98已經累得對鍵盤、鼠標毫無反應。

  我可以得出這麼一個結論:對於32位以上的應用程序,“內存耗盡”錯誤處理程序毫無用處。這下可把Unix和Windows程序員們樂壞了:反正錯誤處理程序不起作用,我就不寫了,省了很多麻煩。

  我不想誤導讀者,必須強調:不加錯誤處理將導致程序的質量很差,千萬不可因小失大。

void main(void)
{
 float *p = NULL;
 while(TRUE)
 {
  p = new float[1000000];
  cout << “eat memory” << endl;
  if(p==NULL)
   exit(1);
 }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章