7.1 內(nèi)存分配方式
(1)從靜態(tài)存儲(chǔ)區(qū)域分配。內(nèi)存在程序編譯的時(shí)候就已經(jīng)分配好,這塊內(nèi)存在程序的整個(gè)運(yùn)行期間都存在。例如全局變量,static變量。
(2)在棧上創(chuàng)建。在執(zhí)行函數(shù)時(shí),函數(shù)內(nèi)局部變量的存儲(chǔ)單元都可以在棧上創(chuàng)建,函數(shù)執(zhí)行結(jié)束時(shí)這些存儲(chǔ)單元自動(dòng)被釋放。棧內(nèi)存分配運(yùn)算內(nèi)置于處理器的指令集中,效率很高,但是分配的內(nèi)存容量有限。
(3)從堆上分配,亦稱動(dòng)態(tài)內(nèi)存分配。程序在運(yùn)行的時(shí)候用malloc或new申請(qǐng)任意多少的內(nèi)存,程序員自己負(fù)責(zé)在何時(shí)用free或delete釋放內(nèi)存。動(dòng)態(tài)內(nèi)存的生存期由我們決定,使用非常靈活,但問題也最多。
7.2常見的內(nèi)存錯(cuò)誤及其對(duì)策
- 內(nèi)存分配未成功,卻使用了它
內(nèi)存分配會(huì)不成功,通常的解決方法是在使用內(nèi)存前檢查指針是否為NULL。如果指針p是函數(shù)的參數(shù),那么在函數(shù)的入口處用assert(p != NULL)進(jìn)行防錯(cuò)處理。
- 內(nèi)存分配雖然成功,但是尚未初始化就引用它。
犯這種錯(cuò)誤主要有兩個(gè)起因:一是沒有初始化的觀念;二是誤以為內(nèi)存的缺省初值
全為零,導(dǎo)致引用初值錯(cuò)誤(例如數(shù)組)。
- 內(nèi)存分配成功并且已經(jīng)初始化,但操作越過了內(nèi)存的邊界。
- 忘記了釋放內(nèi)存,造成內(nèi)存泄露。
- 釋放了內(nèi)存卻繼續(xù)使用它。
【規(guī)則7-2-1】用 malloc 或 new 申請(qǐng)內(nèi)存之后,應(yīng)該立即檢查指針值是否為 NULL。防止使用指針值為 NULL 的內(nèi)存。
【規(guī)則7-2-2】不要忘記為數(shù)組和動(dòng)態(tài)內(nèi)存賦初值。防止將未被初始化的內(nèi)存作為右值使用。
【規(guī)則7-2-3】避免數(shù)組或指針的下標(biāo)越界,特別要當(dāng)心發(fā)生“多1”或者“少1”操作。
【規(guī)則7-2-4】動(dòng)態(tài)內(nèi)存的申請(qǐng)與釋放必須配對(duì),防止內(nèi)存泄漏。
【規(guī)則7-2-5】用free或delete釋放了內(nèi)存之后,立即將指針設(shè)置為NULL,防止產(chǎn)生“野指針”。
7.3指針與數(shù)組的對(duì)比
7.3.1 修改內(nèi)容
7.3.2 內(nèi)容復(fù)制與比較
不能對(duì)數(shù)組名進(jìn)行直接復(fù)制與比較。
7.3.3 計(jì)算內(nèi)存容量
7.4指針參數(shù)是如何傳遞內(nèi)存的?
如果函數(shù)的參數(shù)是一個(gè)指針,不要指望用該指針去申請(qǐng)動(dòng)態(tài)內(nèi)存。
正確的方法可以使用指向指針的指針,或者可以用函數(shù)返回值來傳遞動(dòng)態(tài)內(nèi)存。不要用return語(yǔ)句返回指向“棧內(nèi)存”的指針,因?yàn)樵搩?nèi)存在函數(shù)結(jié)束時(shí)自動(dòng)消亡。
7.5 free和delete把指針怎么啦?
free/delete掉的指針應(yīng)該賦NULL值。
7.6 動(dòng)態(tài)內(nèi)存會(huì)被自動(dòng)釋放嗎?
(1)指針消亡了,并不表示它所指的內(nèi)存會(huì)被自動(dòng)釋放。
(2)內(nèi)存被釋放了,并不表示指針會(huì)消亡或者成了NULL指針。
7.7 杜絕“野指針”
7.8 有了malloc/free為什么還要new/delete ?
對(duì)于非內(nèi)部數(shù)據(jù)類型的對(duì)象而言,光用maloc/free無法滿足動(dòng)態(tài)對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù),對(duì)象在消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù)。由于malloc/free是庫(kù)函數(shù)而不是運(yùn)算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加于malloc/free。因此C++語(yǔ)言需要一個(gè)能完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new,以及一個(gè)能完成清理與釋放內(nèi)存工作的運(yùn)算符delete。注意new/delete不是庫(kù)函數(shù)。