C++ 動態記憶體
瞭解動態記憶體在 C++ 中是如何工作的是成為一名合格的 C++ 程式員必不可少的。C++ 程式中的記憶體分為兩個部分:
- 棧:在函數內部聲明的所有變數都將佔用棧記憶體。
- 堆:這是程式中未使用的記憶體,在程式運行時可用於動態分配記憶體。
很多時候,您無法提前預知需要多少記憶體來存儲某個定義變數中的特定資訊,所需記憶體的大小需要在運行時才能確定。
在 C++ 中,您可以使用特殊的運算符為給定類型的變數在運行時分配堆內的記憶體,這會返回所分配的空間地址。這種運算符即 new 運算符。
如果您不再需要動態分配的記憶體空間,可以使用 delete 運算符,刪除之前由 new 運算符分配的記憶體。
new 和 delete 運算符
下麵是使用 new 運算符來為任意的數據類型動態分配記憶體的通用語法:
new data-type;
在這裏,data-type 可以是包括數組在內的任意內置的數據類型,也可以是包括類或結構在內的用戶自定義的任何數據類型。讓我們先來看下內置的數據類型。例如,我們可以定義一個指向 double 類型的指針,然後請求記憶體,該記憶體在執行時被分配。我們可以按照下麵的語句使用 new 運算符來完成這點:
double* pvalue = NULL;
pvalue = new double;
如果自由存儲區已被用完,可能無法成功分配記憶體。所以建議檢查 new 運算符是否返回 NULL 指針,並採取以下適當的操作:
double* pvalue = NULL;
if( !(pvalue = new double ))
{
cout << "Error: out of memory." <<endl;
exit(1);
}
malloc() 函數在 C 語言中就出現了,在 C++ 中仍然存在,但建議儘量不要使用 malloc() 函數。new 與 malloc() 函數相比,其主要的優點是,new 不只是分配了記憶體,它還創建了對象。
在任何時候,當您覺得某個已經動態分配記憶體的變數不再需要使用時,您可以使用 delete 操作符釋放它所佔用的記憶體,如下所示:
delete pvalue; // 釋放 pvalue 所指向的記憶體
下麵的實例中使用了上面的概念,演示了如何使用 new 和 delete 運算符:
實例
#include <iostream>
using namespace std;
int main ()
{
double* pvalue = NULL;
pvalue = new double;
*pvalue = 29494.99;
cout << "Value of pvalue : " << *pvalue << endl;
delete pvalue;
return 0;
}
當上面的代碼被編譯和執行時,它會產生下列結果:
Value of pvalue : 29495
數組的動態記憶體分配
假設我們要為一個字元數組(一個有 20 個字元的字串)分配記憶體,我們可以使用上面實例中的語法來為數組動態地分配記憶體,如下所示:
char* pvalue = NULL; // 初始化為 null 的指針
pvalue = new char[20]; // 為變數請求記憶體
要刪除我們剛才創建的數組,語句如下:
delete [] pvalue; // 刪除 pvalue 所指向的數組
下麵是 new 操作符的通用語法,可以為多維數組分配記憶體,如下所示:
一維數組
int *array=new int [m];
delete [] array;
二維數組
int **array
array = new int *[m];
for( int i=0; i<m; i++ )
{
array[i] = new int [n] ;
}
for( int i=0; i<m; i++ )
{
delete [] arrary[i];
}
delete [] array;
二維數組實例測試:
實例
#include <iostream>
using namespace std;
int main()
{
int **p;
int i,j;
p = new int *[4];
for(i=0;i<4;i++){
p[i]=new int [8];
}
for(i=0; i<4; i++){
for(j=0; j<8; j++){
p[i][j] = j*i;
}
}
for(i=0; i<4; i++){
for(j=0; j<8; j++)
{
if(j==0) cout<<endl;
cout<<p[i][j]<<"\t";
}
}
for(i=0; i<4; i++){
delete [] p[i];
}
delete [] p;
return 0;
}
三維數組
int ***array;
array = new int **[m];
for( int i=0; i<m; i++ )
{
array[i] = new int *[n];
for( int j=0; j<n; j++ )
{
array[i][j] = new int [h];
}
}
for( int i=0; i<m; i++ )
{
for( int j=0; j<n; j++ )
{
delete[] array[i][j];
}
delete[] array[i];
}
delete[] array;
三維數組測試實例:
實例
#include <iostream>
using namespace std;
int main()
{
int i,j,k;
int ***p;
p = new int **[2];
for(i=0; i<2; i++)
{
p[i]=new int *[3];
for(j=0; j<3; j++)
p[i][j]=new int[4];
}
for(i=0; i<2; i++)
{
for(j=0; j<3; j++)
{
for(k=0;k<4;k++)
{
p[i][j][k]=i+j+k;
cout<<p[i][j][k]<<" ";
}
cout<<endl;
}
cout<<endl;
}
for(i=0; i<2; i++)
{
for(j=0; j<3; j++)
{
delete [] p[i][j];
}
}
for(i=0; i<2; i++)
{
delete [] p[i];
}
delete [] p;
return 0;
}
對象的動態記憶體分配
對象與簡單的數據類型沒有什麼不同。例如,請看下麵的代碼,我們將使用一個對象數組來理清這一概念:
實例
#include <iostream>
using namespace std;
class Box
{
public:
Box() {
cout << "調用構造函數!" <<endl;
}
~Box() {
cout << "調用析構函數!" <<endl;
}
};
int main( )
{
Box* myBoxArray = new Box[4];
delete [] myBoxArray;
return 0;
}
如果要為一個包含四個 Box 對象的數組分配記憶體,構造函數將被調用 4 次,同樣地,當刪除這些對象時,析構函數也將被調用相同的次數(4次)。
當上面的代碼被編譯和執行時,它會產生下列結果:
調用構造函數!
調用構造函數!
調用構造函數!
調用構造函數!
調用析構函數!
調用析構函數!
調用析構函數!
調用析構函數!