**********************************
原文連結:http://www.cplusplus.com/doc/tutorial/
**********************************
直道現在,在我們的所有程式中,我所擁有的所有有效記憶體就是被我們聲明的變數,在來源程式中就已經確定了他們全部的大小,在程式運行之前。但是,如果我們需要一個塊能在運行期才能確定大小的一個可變總的記憶體該怎麼辦呢?例如,在我們需要一些使用者的輸入來決定所需記憶體空間的總量的情況。這個答案就是
動態記憶體(
dynamic memory
),為此C++整合了操作符
new和
delete。
Your Ad Here
操作符
new
和
new[]為了請求動態記憶體我們使用操作符new。new後面跟隨一個資料類型說明符,並且——如果請求多於1個元素的一個序列——這些元素的個數被括在方括弧[]中。它返回指向被分配的新記憶體塊的開始的一個指標。它的形式為:
pointer = new type
pointer = new type [elements]
第一個運算式被用來分配包含單獨一個
type類型的元素的記憶體。第二個則用來分配
type類型元素的一塊記憶體,其中
elements是一個整型值指出這些元素的個數。例如:
| int * bobby;bobby = new int [5]; |
在這種情況中,系統為5個
int型元素動態地分配空間,並返回一個指向這個序列第一個元素的一個指標,就是被賦給
bobby的那個。因此,現在,
bobby指向一個有效記憶體塊,這個記憶體塊的空間為5個
int類型的元素。
被
bobby指向的第一個元素可以通過運算式
bobby[0]或運算式
*bobby來訪問。它們兩個是等價就像在關於指標那個節解釋的。第二個元素可以使用
bobby[1]或
*(bobby+1)來訪問,等等……你可能正驚訝於聲明一個普通數組和給指標分配動態記憶體的不同,就像我們剛剛做的那樣。最主要的不同是:數組的大小是一個常量值,這就限制了它的大小為我們在設計程式時決定的值,在它運行之前;反過來動態記憶體分配允許我們在程式執行期間(運行時)分配記憶體,使用任何變數或常量作為它的大小。被我們程式請求的動態記憶體被系統從記憶體堆中分配。但是,電腦記憶體是一個有限的資源,它可以被耗盡。因此,有一些用來檢測我們的分配記憶體的請求成功與否的機制是非常重要的。C++提供了兩種標準方法來檢測分配是否成功:一種是通過處理異常。使用這種方法,當分配失敗是拋出一個
bad_alloc類型的異常。異常是一種強大C++特性,將在這個指南的稍後闡述。但是現在,你應該瞭解:如果這個異常被拋出,並且沒有任何具體的處理者處理的話,這個程式的運行將被終止。這個異常方法是被
new使用的預設方法,並且是被像這樣用在一個聲明中:
| bobby = new int [5]; // if it fails an exception is thrown |
另一種方法被稱為“
nothrow
(不拋)”,當它被使用且一個記憶體配置失敗時將發生的不是拋出一個
bad_alloc異常或終止程式,而是
new返回的指標是一個
null指標,並且程式將繼續運行。這個方法可以通過使用一個特殊的叫做
nothrow的對象作為
new的參數來指明:
| bobby = new (nothrow) int [5]; |
在這種情況,如果分配這塊記憶體失敗,這個失敗可以通過檢查是否
bobby帶有一個
null指標值來發現:
| int * bobby;bobby = new (nothrow) int [5];if (bobby == 0) { // error assigning memory. Take measures. }; |
這個
nothrow方法比異常方法要求更多的工作,因為每一個記憶體配置後都必須檢查傳回值,但是我將在我們的例子中使用它,由於它的簡單。總之這個方法對於更大的工程會變得使人討厭,而異常方法通常更好。異常方法將在這篇指南的稍後進行詳細的說明。
操作符
delete
和
delete[]因為對動態記憶體的需要通常局限在一個程式中的特定時刻,一旦它不再被需要它應該被釋放,以使那塊記憶體變的再一個對其他動態記憶體的請求有效。這是操作符
delete的目的,它的形式是:
| delete pointer;delete [] pointer; |
第一運算式用來刪除為一個單獨元素分配的記憶體,而第二個用來釋放為一組元素分配的記憶體。被作為實參傳遞給
delete的必須是一個指向一個在先前由
new分配的記憶體塊的指標,或一個
null指標(在
null指標的情況中,
delete不產生任何影響)。
| // rememb-o-matic#include <iostream>using namespace std; int main (){ int i,n; int * p; cout << "How many numbers would you like to type? "; cin >> i; p= new (nothrow) int[i]; if (p == 0) cout << "Error: memory could not be allocated"; else { for (n=0; n<i; n++) { cout << "Enter number: "; cin >> p[n]; } cout << "You have entered: "; for (n=0; n<i; n++) cout << p[n] << ", "; delete[] p; } return 0;} |
How many numbers would you like to type? 5Enter number : 75Enter number : 436Enter number : 1067Enter number : 8Enter number : 32You have entered: 75, 436, 1067, 8, 32, |
注意在
new語句中方括弧中的值是一個變數(
i),它的值由使用者輸入,而不是一個常量:
但是使用者可能為i輸入一個對於我們的系統來說太大的值,而使我們的系統無法處理它。例如,當我嘗試對於問題“How many numbers(多少個數字)”給出一個10億的值的時候,我的系統不能為這個程式分配如此多的記憶體,而我得到了我們為這種情況準備好的文本資訊(Error:memory could be allocated)。記住:當我們嘗試分配記憶體而沒有在new運算式中指明nothrow形參的情況中,一個異常可能被拋出,如果它沒有被處理將終止程式的運行。
一直檢查是否一個動態記憶體塊被成功的分配了是一個好的習慣。因此,如果你使用
nothrow方法,你應該一直檢測被返回的指標的值。否則,使用異常方法,雖然你沒有處理這個異常。這樣,程式將會在那一點終止,而不會繼續運行那些假設一塊記憶體已經被分配而實際上它並沒有成功的代碼從而引起意料不到的結果。
在
ANSI-C
中的動態記憶體操作符new和delete只是在C++中的。它們在C語言中是無效的。但是使用純C語言,動態記憶體通過函數malloc、calloc、realloc和free來被使用,這些函數定義在〈cstdlib〉標頭檔中,由於C++是C的一個超集(這個說法不準確——譯者注),這些函數在對C++程式員同樣是有效。被這些函數分配的記憶體塊和通過new返回的不相容,因此每種都需要通過它自己的那組函數或操作符來操縱。