《高質量程式設計指南》第16章記憶體管理
其中,後四小節:16.12 用物件模擬指標,16.13 泛型指標auto_ptr,16.14 帶有引用計數的智慧型指標,16.15 智慧型指標作為容器元素個人感覺比較難,有待以後深入學習。
前面幾小節說的內容很重要,需要時常溫故。
下面是一點筆記內容:
一記憶體的三種分配方式
1 從靜態儲存區域分配。特點:在程式編譯的時候就已經分配好了,這些內存在程式的整個執行期間都存在,如全域性變數、static變數等。
2 在堆疊上分配。特點:在函式執行期間,函式內區域性變數(包括形參)的儲存單元都建立在堆疊上,函式結束時,這些儲存單元自動釋放(堆疊清退)。注意:分配的記憶體容量有限,可能出現堆疊溢位。
3 從堆(heap)或自由儲存空間上分配,也稱動態記憶體分配。特點:在程式執行期間,呼叫malloc或new申請任意數量的記憶體,程式設計師自己掌握釋放記憶體的恰當時機(使用free或delete)。
一般原則:如果使用堆疊儲存和靜態儲存就能滿足應用要求,就不要使用動態儲存。
原因:在堆上動態分配記憶體需要很可觀的額外開銷。p287詳述原因。
二常見的記憶體錯誤及其對策
1 記憶體分配未成功,卻使用了它。
常用的解決辦法是:在使用記憶體之前檢查指標是否為null。如果指標p時函式的引數,那麼在函式的入口處用assert(p!=null)進行檢查以避免輸入非法引數。如果用malloc()或new來申請記憶體,應該用if(p==null)、if(p!=null)或者捕獲異常來進行錯誤處理。
2 記憶體分配雖然成功,但是尚未初始化就使用它。
犯這種錯誤有兩種原因:1 沒有初始化的意識;2 誤以為分配好的記憶體會自動初始化為全0,導致引用初值錯誤。
解決辦法:我們應該在潛意識裡認為全域性物件或靜態物件及其陣列沒有初值,無論用何種方式建立陣列,都別忘了賦初值,即便是賦零值也不可省略,不要嫌麻煩。
3 記憶體分配成功且已經初始化,但操作越過了記憶體的邊界。
例如:在使用陣列時經常發生下標「多1」或者「少1」的操作。特別是在for迴圈語句中,迴圈次數很容易高潮,導致陣列元素訪問越界。
4 忘記了釋放記憶體或者只釋放了部分記憶體,因此造成記憶體洩露
5 釋放了記憶體卻還在繼續使用它。
見p288詳述
規則1 用malloc或new申請記憶體之後,應立即檢查指標值是否為null或者進行異常處理,以防止使用值為null的指標。
規則2 不要忘記初始化指標、陣列和動態記憶體,防止將未初始化的記憶體作為右值使用。
規則3 避免陣列或指標的下標越界,特別當心「多1」或者「少1」的操作。
規則4 動態記憶體的申請和釋放必須配對,防止記憶體洩露。
規則5 用free或delete釋放了記憶體之後,立即將指標設定為null,防止「野指標」。
三free和delete把指標怎麼啦!!!
free和delete只是把指標所指向的記憶體給釋放掉,並沒有把指標本身刪除掉。如果不把這個指標設定為null,這個指標就變成了「野指標」。所以再次強調一定不要忘記初始化指標變數為null或者有效位址。
四、杜絕「野指標」
「野指標」不是null指標,而是指向「非法」記憶體的指標。程式設計師一般不會錯用null指標,因為用if語句很容易判斷。但是「野指標」是很危險的,if語句對它可能不起作用。
「野指標」的成因主要有以下3種:
1 沒有初始化指標變數。任何指標變數剛被建立時不會自動成為null指標,它的預設值是隨機的,它會亂指一氣。所以,指標變數在建立的同時應當初始化,要麼將指標設定為null,要麼讓它指向有效的記憶體。
2 指標p被free()或delete之後,沒有置位null,讓人誤以為p仍然是乙個有效的指標。
3 指標操作超越了變數的作用範圍,這種情況讓人防不勝防。
五malloc / free 和new / delete的不同
1 malloc()與free()是c/c++語言的標準庫函式,new/delete是c++的運算子,它們都可用於申請和釋放動態記憶體。
2 由於malloc()與free()是庫函式而不是運算子,不在編譯器控制許可權之內,不能把呼叫建構函式和析構函式的任務強加給它們。
3 不要企圖用malloc()與free()來完成動態物件的記憶體管理,應該用new/delete。由於內部資料型別的「物件」沒有構造和析構過程,對他們而言new/delete和malloc()/free()是等價的。
六malloc / free的使用要點
函式malloc()的原型如下:
void *malloc(size_t size);
用malloc()申請一塊長度為length的整型陣列的記憶體,程式如下:
int *p = (int *)malloc(sizeof(int) * length);
我們應當把注意力集中在兩個要素上:「型別轉換」和「sizeof」。
1 malloc()函式返回值的型別是void *,所以在呼叫malloc時要顯式地進行型別轉換,將void *轉換成所需的指標型別;
2 malloc()函式本身並不識別要申請的記憶體是什麼型別,它只關心記憶體的總位元組數。在malloc()函式的「()」中使用sizeof運算子是良好的風格。
高質量程式設計指南 c c 語言 筆記之記憶體管理
記憶體的3種分配方式 1.從靜態儲存區域分配 即在編譯程式的時候就已經分配好了,在程式的整個執行期間都存在 全域性變數 static變數 2.在堆疊上分配 函式執行期間分配。堆疊的的分配運算內置於處理器的指令集中,效率很高,失敗率不高,分配的記憶體容量有限,可能出現堆疊溢位。3.從堆或自由儲存空間上...
高質量C C程式設計指南
1.如果引數是指標,且僅作輸入用,則應在型別前加const,以防止該指標在函式體內被意外修改 2.在函式體的 入口處 對引數的有效性進行檢查 在函式體的 出口處 對return語句的正確性和效率進行檢查 3.引用的一些規則如下 1 引用被建立的同時必須被初始化 指標則可以在任何時候被初始化 2 不能...
高質量C C程式設計指南
目錄 前 言.6 第1章檔案結構 11 1.1 版權和版本的宣告 11 1.2 標頭檔案的結構 12 1.3 定義檔案的結構 13 1.4 標頭檔案的作用 13 1.5 目錄結構 14 第2章程式的版式 15 2.1 空行.15 2.2 行.16 2.3 行內的空格 17 2.4 對齊.18 2.5...