《高質量程式設計指南》之記憶體管理讀書筆記

2021-06-20 11:07:58 字數 2573 閱讀 1080

《高質量程式設計指南》第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...