C++ 動態記憶體



深入理解 C++ 中動態記憶體的工作原理對於成為一名優秀的 C++ 程式設計師至關重要。C++ 程式中的記憶體分為兩個部分:

  • - 在函式內部宣告的所有變數都將從棧中佔用記憶體。

  • - 這是程式的未使用記憶體,可以在程式執行時動態分配記憶體。

很多時候,您事先並不知道需要多少記憶體來儲存定義變數中的特定資訊,並且所需記憶體的大小可以在執行時確定。

您可以使用 C++ 中的一個特殊運算子在執行時在堆中為給定型別的變數分配記憶體,該運算子返回已分配空間的地址。此運算子稱為new運算子。

如果您不再需要動態分配的記憶體,可以使用delete運算子,它將釋放之前由 new 運算子分配的記憶體。

new 和 delete 運算子

以下是一般語法,用於使用new運算子為任何資料型別動態分配記憶體。

new data-type;

這裡,data-type可以是任何內建資料型別,包括陣列或任何使用者定義的資料型別,包括類或結構體。讓我們從內建資料型別開始。例如,我們可以定義一個指向 double 型別的指標,然後請求在執行時分配記憶體。我們可以使用以下語句使用new運算子來做到這一點:

double* pvalue  = NULL; // Pointer initialized with null
pvalue  = new double;   // Request memory for the variable

如果空閒儲存已用完,則記憶體可能無法成功分配。因此,最好檢查 new 運算子是否返回 NULL 指標並採取適當的操作,如下所示:

double* pvalue  = NULL;
if( !(pvalue  = new double )) {
   cout << "Error: out of memory." <<endl;
   exit(1);
}

來自 C 的malloc()函式仍然存在於 C++ 中,但建議避免使用 malloc() 函式。new 相對於 malloc() 的主要優勢在於,new 不僅分配記憶體,還構造物件,這是 C++ 的主要目的。

在任何時候,當您認為一個已動態分配的變數不再需要時,您可以使用‘delete’運算子釋放它在空閒儲存中佔用的記憶體,如下所示:

delete pvalue;        // Release memory pointed to by pvalue

讓我們將上述概念組合成以下示例,以展示‘new’和‘delete’是如何工作的:

#include <iostream>
using namespace std;

int main () {
   double* pvalue  = NULL; // Pointer initialized with null
   pvalue  = new double;   // Request memory for the variable
 
   *pvalue = 29494.99;     // Store value at allocated address
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // free up the memory.

   return 0;
}

如果我們編譯並執行上述程式碼,這將產生以下結果:

Value of pvalue : 29495

陣列的動態記憶體分配

假設您想為一個字元陣列(即 20 個字元的字串)分配記憶體。使用與上面我們使用的相同的語法,我們可以動態分配記憶體,如下所示。

char* pvalue  = NULL;         // Pointer initialized with null
pvalue  = new char[20];       // Request memory for the variable

要刪除我們剛剛建立的陣列,該語句將如下所示:

delete [] pvalue;             // Delete array pointed to by pvalue

遵循 new 運算子的類似通用語法,您可以為多維陣列分配記憶體,如下所示:

double** pvalue  = NULL;      // Pointer initialized with null 
pvalue  = new double [3][4];  // Allocate memory for a 3x4 array 

但是,釋放多維陣列記憶體的語法仍然與上面相同:

delete [] pvalue;            // Delete array pointed to by pvalue

物件的動態記憶體分配

物件與簡單資料型別沒有什麼不同。例如,考慮以下程式碼,我們將使用物件陣列來闡明這個概念:

#include <iostream>
using namespace std;

class Box {
   public:
      Box() { 
         cout << "Constructor called!" <<endl; 
      }
      ~Box() { 
         cout << "Destructor called!" <<endl; 
      }
};
int main() {
   Box* myBoxArray = new Box[4];
   delete [] myBoxArray; // Delete array

   return 0;
}

如果您要分配四個 Box 物件的陣列,則 Simple 建構函式將被呼叫四次,類似地,在刪除這些物件時,解構函式也將被呼叫相同次數。

如果我們編譯並執行上述程式碼,這將產生以下結果:

Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!
廣告