《 高質量C 程式設計指南 》學習重點六

2021-05-25 06:15:06 字數 4448 閱讀 1341

有了

malloc/free

為什麼還要 ?

malloc與

free

是c++/c

語言的標準庫函式,

new/delete

是c++

對於非內部資料型別的物件而言,光用

maloc/free

無法滿足動態物件的要求。物件在建立的同時要自動執行建構函式,物件在消亡之前要自動執行析構函式。

由於 malloc/free

是庫函式而不是運算 符,不在編譯器控制許可權之內,不能夠把執行建構函式和析構函式的任務強加於

malloc/free。

因此c++

語言需要乙個能完成動態記憶體分配和初 始化工作的運算子

new,以及乙個能完成清理與釋放記憶體工作的運算子

delete

。注意new/delete

不是庫函式。

我們先看一看

malloc/free

和new/delete

如何實現物件的動態記憶體管理,見示例

7-8。

class obj 「

destroy

」<< endl; }

「initialization

」<< endl; }

「destroy

」<< endl; }

}; void usemallocfree(void)

void usenewdelete(void)

示例用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 也 一樣。

記憶體耗盡怎麼辦?

如果在申請動態記憶體時找不到足夠大的記憶體塊,

malloc

和new

將返回null

指標,宣告記憶體申請 失敗。 通常有三種方式處理「記憶體耗盡」問題。 (

1)判斷指標是否為

null

,如果是則馬上用

return

語句終止本函式。 例 如:

void func(void)

… }

(2)判斷指標是否為

null

,如果是則馬上用

exit(1)

終止整個程式的執行。 例如:

void func(void)

… }

(3)為

new和malloc

設定異常處理函式。例如

visual c++

可以用_set_new_hander

函式為new

設定使用者自己定義的異常處理函式,也可以讓

malloc

享用與new

相同的異常處理函式。詳細內容請參考

c++使用手冊。

上述(1)(

2)方式使用最普遍。如果乙個函式內有多處需 要申請動態記憶體,那麼方式(

1)就顯得力不從心(釋放記憶體很麻煩),應該用方式(

2)來處理。

很多人不忍心用

exit(1)

,問:「不編寫出錯處理程式, 讓作業系統自己解決行不行?」

不行。如果發生「記憶體耗盡」這 樣的事情,一般說來應用程式已經無藥可救。如果不用

把壞程式殺死,它可能會害死作業系統。道理如同:如果不把歹徒擊斃,歹徒在老死之前會犯下更多的罪。

有乙個很重要的現象要告訴大家。對於

32位以上的應用程式而言,無論怎樣使用

malloc

與new

,幾乎不可能導致 「記憶體耗盡」。 我在

windows 98

下用visual c++

編寫了測試程式,見示例

7-9。這個程式會無休止地執行下去,根本不會終止。因為

32位作業系統支援「虛存」,記憶體用完了,自 動用硬碟空間頂替。我只聽到硬碟嘎吱嘎吱地響,

window 98

已經累得對鍵盤、滑鼠毫無反應。

我可以得出這麼乙個結論:對於

32位以上的應用程式,「記憶體耗盡」錯誤處 理程式毫無用處。這下可把

unix

和windows

程式設計師們樂壞了:反正錯誤處理程式不起作用,我就不寫了,省了很多麻煩。

void main(void)

} 示例7-9

試圖耗盡作業系統的記憶體

的使用要點

函式malloc 的原型如下:

void * malloc(size_t size);

用malloc 申請一塊長度為length 的整數型別的記憶體,程式如下:

int  *p = (int *) malloc(sizeof(int) * length);

我們應當把注意力集中在兩個要素上:「型別轉換」和「sizeof 」。

malloc

轉 換成所需要的指標型別。

malloc

函式本身並不識別要申 請的記憶體是什麼型別,它只關心記憶體的總位元組數。 我們通常記不住

int, float

等資料型別的變數的確切位元組數。例如

int變數在

16位系統下是

2個位元組,在

32位下是

4個位元組;而

float

變數在16

位系統下是

4個位元組,在

32位下也是

4個位元組。

函 數free

的原型 如下:

void free( void * memblock );

為什麼free 函式不象malloc 函式那樣複雜呢?這是因為指標p 的型別以及 它所指的記憶體的容量事先都是知道的,語句free(p) 能正確地釋放記憶體。如果p 是null 指標,那麼free 對p 無論操作多少次都不會出問題。如果p 不是null 指標,那麼free 對p 連續操作兩次就會導致程式執行錯誤。

的使用要點

運算子new使用起來要比函式

malloc

簡單得多,例如:

int  *p1 = (int *)malloc(sizeof(int) * length);

int  *p2 = new int[length];

這是因為

new內建了

sizeof

、型別轉換和型別安全檢查功能。對於非內部資料型別的物件而言,

new在建立動態物件的同時完成了初始化工 作。如果物件有多個建構函式,那麼

new 的語句也可以有多種形 式。 例如:

class obj

void test(void)

如果用new 建立物件陣列,那麼只能使用物件的無引數建構函式。 例如

建立100 個動態物件

不能寫成

建立100 個動態物件的同時賦初值1

在用delete 釋 放物件陣列時,留意不要丟了符號『 』。 例如

正確的用法

錯誤的用法

後者相當於delete objects[0] ,漏掉了另外99 個物件。

一些心得體會

我認識不少技術不錯的

c++/c

程式設計師,很少有人能拍拍胸脯說通曉 指標與記憶體管理(包括我自己)。我最初學習

c語言時特別怕指標,導致我開發第乙個應用軟體(約1萬行

c**)時沒有使用乙個指標,全用陣列來頂替 指標,實在蠢笨得過分。躲避指標不是辦法,後來我改寫了這個軟體,**量縮小到原先的一半。

我的經驗教訓是: (

1)越是怕指標,就越要使用指標。不會正確使用指標,肯定算不上是合格的程式設計師。 (

2)必須養成「使用偵錯程式逐步跟蹤程式」的習慣,只有這樣才能發現問題的本質。

《 高質量C 程式設計指南 》學習重點十

物件 object 是類 class 的乙個例項 instance 如果將物件比作房子,那麼類就是房子的設計圖紙。所以物件導向設計的重點是類的設計,而不是物件的設計。對於 c 程式而言,設計孤立的類是比較容易的,難的是正確設計基類及其派生類。本章僅僅論述 繼承 inheritance 和 組合 co...

高質量C 程式設計指南 》學習重點四

7 章 記憶體管理 記憶體分配方式有三種 從靜態儲存區域分配。內 存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例 如全域性變數,static 變數。在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單 元自動被釋放。棧記憶體分配運算內...

《 高質量C 程式設計指南 》學習重點十

物件 object 是類 class 的乙個例項 instance 如果將物件比作房子,那麼類就是房子的設計圖紙。所以物件導向設計的重點是類的設計,而不是對 象的設計。對於c 程式而言,設計孤立的類是比較容易的,難的是正確設計基類及其派生類。本章僅僅論述 繼承 inheritance 和 組合 co...