動態 記憶體管理

2021-07-06 06:28:14 字數 3538 閱讀 7126

定義變數時,必須制定其資料型別和名字。而動態建立物件時,只需指定其資料型別,而不必為該物件命名。取而代之的是,new表示式返回指向新建立物件的指標,我們通過該指標來訪問此物件。

int i;                    

int *pi = new

int;

這個new表示式在自由儲存區中分配建立了乙個整型物件,並返回此物件的位址,並用該位址初始化指標pi。

動態建立的物件可用初始化變數的方式實現初始化:

int i(1024);

int *pi = new

int(1024);

string s(10,'9');

string *ps = new

string(10,'9');

c++使用直接初始化語法規則初始化動態建立的物件。如果提供了初值,new表示式分配到所需要的記憶體後,用給定的初值初始化該記憶體空間。pi所指向的新建立物件將被初始化為1024,ps指向的物件初始化為十個9的字串。

如果不提供顯示初始化,動態建立的物件與在函式內定義的變數初始化方式相同。對於類型別物件,用該類的預設建構函式初始化;而內建型別的物件則無初始化。

string *ps = new

string;

int *pi = new

int; //pi points to an uninitialized int

通常,除了對其複製之外,對未初始化的物件所關聯的值的的任何使用都是沒有定義的。

同樣也可對動態建立的物件做值初始化:

string *ps = new

string(); // initialized to empty string

int *pi = new int(); // pi points to an int value-initialized to

0cls *pc = new cls(); // pc points to a value-initialized object of

type cls

以上表明程式設計師想通過在型別名後面使用一對內容為空的圓括號對動態建立的物件做值初始化。內容為空的圓括號表示雖然要做初始化,但實際上並未提供特定的初值。對於提供了預設建構函式的類型別,沒有必要對其物件進行值初始化:無論程式是明確地不初始化還是要求進行值初始化,都會自動呼叫其預設建構函式初始化該物件。而對於內建型別或沒有定義預設建構函式的型別,採用不同初始化方式則有顯著的差別:

int *pi = new

int; // pi points to an uninitialized int

int *pi = new

int(); // pi points to an int value-initialized to 0

第乙個語句的int型變數沒有初始化,而第二個語句的int型變數則被初始化為0。

儘管現代機器的記憶體容量越來越大,但是自由儲存區宗有可能被耗盡。如果程式用完了可用的記憶體,new表示式就有可能失敗。如果new表示式無法獲取需要的記憶體空間,系統將拋出名為bad_alloc的異常。

動態建立的物件用完後,程式設計師必須顯示地將該物件占用的記憶體返回給自由儲存區。c++提供了delete表示式釋放指標所指向的位址空間。

delete pi;

該命令釋放pi指向的int型物件所占用的記憶體空間。如果指標指向不是用new分配的記憶體位址,則在該指標上使用delete是不合法的。

c++沒有明確定義如何釋放指向不是用new分配的記憶體位址的指標。下面提供了一些安全的和不安全的delete表示式。

int i;

int *pi = &i;

string str = "dwarves";

double *pd = new

double(33);

delete str; //error: str is not dymamic object

delete pi; //error: pi refers to a local

delete pd; //ok

值得注意的是:編譯器可能會拒絕編譯str的delete語句。編譯器知道str並不是乙個指標。因此會在編譯時就能檢查出這個錯誤。第二個錯誤則比較隱蔽:通常來說,編譯器不能斷定乙個指標指向什麼型別的物件,因此儘管這個語句是錯誤的,但在大部分編譯器上仍能通過。

如果指標的值為0,則在其上做delete操作是合法的,但這樣做沒有任何意義:

int *ip = 0;

delete ip; // ok

c++中,刪除0值的指標是安全的。

執行語句

delete p;

後,p變成不確定的指標。在很多機器上,儘管p值沒有明確定義,但仍然存放了它之前所指向物件的位址,然而p所指向的記憶體已經釋放,因此p不再有效。刪除指標後,該指標變成懸垂指標。懸垂指標指向曾經存放物件的記憶體。但該物件已經不再存在了。懸垂指標往往導致程式錯誤,而且很難檢測出來。

一旦刪除了指標所指向的物件,立即將指標置為0,這樣就非常清楚地表明指標不再指向任何物件。

c++允許動態建立const物件:

const int *pci = new const int(1024);

與其他常量一樣,動態建立的const物件必須在建立時初始化,並且一經過初始化,其值就不能再修改。上述new表示式返回指向int型const物件的指標。與其他const物件的位址一樣,由於new返回的位址上存放的是const物件,因此該位址只能賦給指向const的指標。

對於類型別的const動態物件,如果該類提供了預設的建構函式,則此物件可隱式初始化:

const string *pcs = new const string;

new 表示式沒有顯示初始化 pcs 所指向的物件,而是隱式地將 pcs 所指向的物件初始化為空的string物件。內建型別物件或未提供預設建構函式的類型別物件必須顯示初始化。

警告:動態記憶體的管理容易出錯

下面三種常見的程式錯誤都與動態記憶體分配有關:

(1) 刪除(delete)指向動態分配記憶體的智真失敗,因而無法將該塊記憶體返回給自由儲存區。刪除動態記憶體失敗為「記憶體洩露(memory leak)」。記憶體洩露很難發現,一般需等應用程式執行一段時間後,耗盡了所有記憶體空間時,記憶體洩漏才會顯露出來。

(2)讀寫已刪除的物件。如果刪除指標所指向的物件之後,將指標置為0值,則比較容易檢測出這類錯誤。

(3)對同乙個記憶體空間使用兩次delete表示式。當兩個指標指向同乙個動態建立的物件,刪除時就會發生錯誤。如果在其中乙個指標上做delete運算,將該物件的記憶體空間返還給自由儲存區,然後接著delete第二個指標,此時自由儲存區可能會被破壞。

操縱動態分配的記憶體時,很容易發生上述錯誤,但這些錯誤卻很難以跟蹤和修正。

儘管程式設計師不能改變const物件的值,但可撤銷物件本身。如同其他動態物件一樣,const動態物件也是使用刪除指標來釋放的:

delete pci;

及時delete表示式的運算元是指向int 型const 物件的指標,該語句同樣有效地**pci所指向的內容。

動態記憶體管理

首先應該明白物件的三種內部的儲存方式 自動儲存,靜態儲存,和動態儲存。當執行離開當期程式塊的時候,堆疊指標返回到它進入程式塊 之前的地方,有效的銷毀了那個程式塊的自動變數。重新進入這個塊會再次建立所有的自動變數。靜態物件宣告或者在檔案域中。動態物件是存在系統呼叫 的在執行期中建立並且儲存在堆中,這是...

動態記憶體管理

c語言使用malloc calloc realloc free進行動態記憶體管理。void test c 通過new和delete動態管理記憶體。new delete動態管理物件。new delete動態管理物件陣列。void test void test int globalvar 1 stati...

動態記憶體管理

1 malloc free和new delete之間關係和差異。共同點 他們都是動態管理記憶體的入口 不同點 1 malloc free是c c 的標準庫函式,而 new delete是c 操作符 2 malloc free使用時要自己對於型別大小進行計算,返回值為void new delete使用...