版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
動(dòng)態(tài)內(nèi)存分配和深復(fù)制第一頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存分配
堆內(nèi)存的分配與釋放
堆對(duì)象與構(gòu)造函數(shù)
淺拷貝與深拷貝
C/C++定義了4個(gè)內(nèi)存區(qū)間:代碼區(qū),全局變量與靜態(tài)變量區(qū),局部變量區(qū)即棧區(qū),動(dòng)態(tài)存儲(chǔ)區(qū),即堆(heap)區(qū)或自由存儲(chǔ)區(qū)(freestore)。通常定義變量(或?qū)ο螅?,編譯器在編譯時(shí)都可以根據(jù)該變量(或?qū)ο螅┑念愋椭浪鑳?nèi)存空間的大小,從而系統(tǒng)在適當(dāng)?shù)臅r(shí)候?yàn)樗麄兎峙浯_定的存儲(chǔ)空間。這種內(nèi)存分配稱為靜態(tài)存儲(chǔ)分配有些操作對(duì)象只有在程序運(yùn)行時(shí)才能確定,這樣編譯器在編譯時(shí)就無(wú)法為他們預(yù)定存儲(chǔ)空間,只能在程序運(yùn)行時(shí),系統(tǒng)根據(jù)運(yùn)行時(shí)的要求進(jìn)行內(nèi)存分配,這種方法稱為動(dòng)態(tài)存儲(chǔ)分配。所有動(dòng)態(tài)存儲(chǔ)分配都在堆區(qū)中進(jìn)行。第二頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放
當(dāng)程序運(yùn)行到需要一個(gè)動(dòng)態(tài)分配的變量或?qū)ο髸r(shí),必須向系統(tǒng)申請(qǐng)取得堆中的一塊所需大小的存貯空間,用于存貯該變量或?qū)ο?。?dāng)不再使用該變量或?qū)ο髸r(shí),也就是它的生命結(jié)束時(shí),要顯式釋放它所占用的存貯空間,這樣系統(tǒng)就能對(duì)該堆空間進(jìn)行再次分配,做到重復(fù)使用有限的資源。在C++中,申請(qǐng)和釋放堆中分配的存貯空間,分別使用new和delete的兩個(gè)運(yùn)算符來(lái)完成,其使用的格式如下:指針變量名=new類型名(初始化式);delete指針名;
new運(yùn)算符返回的是一個(gè)指向所分配類型變量(對(duì)象)的指針。對(duì)所創(chuàng)建的變量或?qū)ο螅际峭ㄟ^(guò)該指針來(lái)間接操作的,而動(dòng)態(tài)創(chuàng)建的對(duì)象本身沒(méi)有名字。
第三頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放一般定義變量和對(duì)象時(shí)要用標(biāo)識(shí)符命名,稱命名對(duì)象,而動(dòng)態(tài)的稱無(wú)名對(duì)象(請(qǐng)注意與棧區(qū)中的臨時(shí)對(duì)象的區(qū)別,兩者完全不同:生命期不同,操作方法不同,臨時(shí)變量對(duì)程序員是透明的)。堆區(qū)是不會(huì)自動(dòng)在分配時(shí)做初始化的(包括清零),所以必須用初始化式(initializer)來(lái)顯式初始化。new表達(dá)式的操作序列如下:從堆區(qū)分配對(duì)象,然后用括號(hào)中的值初始化該對(duì)象。從堆區(qū)分配對(duì)象時(shí),new表達(dá)式調(diào)用庫(kù)操作符new()。例如:int*pi=newint(0);它與下列代碼序列大體等價(jià):intival=0;int*pi=&ival;只是pi現(xiàn)在所指向的變量是由庫(kù)操作符new()分配的,位于程序的堆區(qū)中,并且該對(duì)象未命名。第四頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放堆0Pi下面看演示:1.用初始化式(initializer)來(lái)顯式初始化int*pi=newint(0);2.當(dāng)pi生命周期結(jié)束時(shí),必須釋放pi所指向的目標(biāo):
deletepi;注意這時(shí)釋放了pi所指的目標(biāo)的內(nèi)存空間,也就是撤銷了該目標(biāo),稱動(dòng)態(tài)內(nèi)存釋放(dynamicmemorydeallocation),但指針pi本身并沒(méi)有撤銷,它自己仍然存在,該指針?biāo)純?nèi)存空間并未釋放。第五頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放
對(duì)于數(shù)組進(jìn)行動(dòng)態(tài)分配的格式為:指針變量名=new類型名[下標(biāo)表達(dá)式];delete[]指向該數(shù)組的指針變量名;兩式中的方括號(hào)是非常重要的,兩者必須配對(duì)使用,如果delete語(yǔ)句中少了方括號(hào),因編譯器認(rèn)為該指針是指向數(shù)組第一個(gè)元素的指針,會(huì)產(chǎn)生回收不徹底的問(wèn)題(只回收了第一個(gè)元素所占空間),加了方括號(hào)后就轉(zhuǎn)化為指向數(shù)組的指針,回收整個(gè)數(shù)組。delete[]的方括號(hào)中不需要填數(shù)組元素?cái)?shù),系統(tǒng)自知。即使寫(xiě)了,編譯器也忽略。請(qǐng)注意“下標(biāo)表達(dá)式”不是常量表達(dá)式,即它的值不必在編譯時(shí)確定,可以在運(yùn)行時(shí)確定。第六頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放【例7.1】動(dòng)態(tài)數(shù)組的建立與撤銷#include<iostream.h>#include<string.h>voidmain(){ intn; char*pc; cout<<"請(qǐng)輸入動(dòng)態(tài)數(shù)組的元素個(gè)數(shù)"<<endl;
cin>>n;
//在運(yùn)行時(shí)確定,可輸入17
pc=newchar[n];
//申請(qǐng)17個(gè)字符(可裝8個(gè)漢字和一個(gè)結(jié)束符)的內(nèi)存空間
strcpy(pc,"堆內(nèi)存的動(dòng)態(tài)分配"); cout<<pc<<endl; delete[]pc;//釋放pc所指向的n個(gè)字符的內(nèi)存空間
return;
}第七頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放動(dòng)態(tài)分配數(shù)組有三個(gè)特點(diǎn):變量n在編譯時(shí)沒(méi)有確定的值,而是在運(yùn)行中輸入,按運(yùn)行時(shí)所需分配堆空間,這一點(diǎn)是動(dòng)態(tài)分配的優(yōu)點(diǎn),可克服數(shù)組“大開(kāi)小用”的弊端,在表、排序與查找中的算法,若用動(dòng)態(tài)數(shù)組,通用性更佳。delete[]pc是將n個(gè)字符的空間釋放,而用deletepc則只釋放了一個(gè)字符的空間;如果有一個(gè)char*pc1,令pc1=p,同樣可用delete[]pc1來(lái)釋放該空間。盡管C++不對(duì)數(shù)組作邊界檢查,但在堆空間分配時(shí),對(duì)數(shù)組分配空間大小是紀(jì)錄在案的。沒(méi)有初始化式(initializer),不可對(duì)數(shù)組初始化。
第八頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放多維數(shù)組動(dòng)態(tài)分配:new類型名[下標(biāo)表達(dá)式1][下標(biāo)表達(dá)式2]……;建立一個(gè)動(dòng)態(tài)三維數(shù)組float(*cp)[30][20];//指向一個(gè)30行20列數(shù)組的指針cp=newfloat[15][30][20];
//建立由15個(gè)30*20數(shù)組組成的數(shù)組;注意cp等效于三維數(shù)組名,但沒(méi)有指出其邊界,即最高維的元素?cái)?shù)量,就像指向字符的指針即等效一個(gè)字符串,不要把指向字符的指針,說(shuō)成指向字符串的指針。這與數(shù)組的嵌套定義相一致。第九頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放比較:float(*cp)[30][20];//三級(jí)指針;float(*bp)[20];//二級(jí)指針;cp=newfloat[1][20][30];bp=newfloat[30][20];兩個(gè)數(shù)組都是由600個(gè)浮點(diǎn)數(shù)組成,前者是只有一個(gè)元素的三維數(shù)組,每個(gè)元素為30行20列的二維數(shù)組,而另一個(gè)是有30個(gè)元素的二維數(shù)組,每個(gè)元素為20個(gè)元素的一維數(shù)組。刪除這兩個(gè)動(dòng)態(tài)數(shù)組可用下式:delete[]cp;//刪除(釋放)三維數(shù)組;delete[]bp;//刪除(釋放)二維數(shù)組;第十頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放【例】動(dòng)態(tài)創(chuàng)建和刪除一個(gè)m*n個(gè)元素的數(shù)組。采用指針數(shù)組方式來(lái)完成二維數(shù)組的動(dòng)態(tài)創(chuàng)建。constintm=4;//行數(shù)constintn=6;//列數(shù)先看二維數(shù)組的動(dòng)態(tài)創(chuàng)建:voidmain(){double**data;//如果改成double(*data)[n];后面如何改動(dòng)
data=newdouble*[m];
//設(shè)置行
if((data)==0){cout<<"Couuldnotallocate.Bye...";return;}for(intj=0;j<m;j++){
data[j]=newdouble[n];
//設(shè)置列
if(data[j]==0){cout<<"Couuldnotallocate.Bye...";return;}}
for(inti=0;i<m;i++)for(intj=0;j<n;j++){data[i][j]=i*n+j;//初始化數(shù)組元素
cout<<data[i][j]<<endl};de_allocate(data);return;}第十一頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放再看二維數(shù)組的撤銷與內(nèi)存釋放:voidde_allocate(double**data){for(inti=0;i<m;i++)delete[]data[i];//注意撤銷次序,先列后行,與設(shè)置相反
delete[]data;}在VC++平臺(tái)上演示本例。指針使用的幾個(gè)問(wèn)題:1.動(dòng)態(tài)分配失敗。返回一個(gè)空指針(NULL),表示發(fā)生了異常,堆資源不足,分配失敗。2.指針刪除與堆空間釋放。刪除一個(gè)指針p(deletep;)實(shí)際意思是刪除了p所指的目標(biāo)(變量或?qū)ο蟮龋?,釋放了它所占的堆空間,而不是刪除p本身,釋放堆空間后,p成了空懸指針。第十二頁(yè),共二十三頁(yè),2022年,8月28日
堆內(nèi)存的分配與釋放3.內(nèi)存泄漏(memoryleak)和重復(fù)釋放。new與delete是配對(duì)使用的,delete只能釋放堆空間。如果new返回的指針值丟失,則所分配的堆空間無(wú)法回收,稱內(nèi)存泄漏,同一空間重復(fù)釋放也是危險(xiǎn)的,因?yàn)樵摽臻g可能已另分配,所以必須妥善保存new返回的指針,以保證不發(fā)生內(nèi)存泄漏,也必須保證不會(huì)重復(fù)釋放堆內(nèi)存空間。4.動(dòng)態(tài)分配的變量或?qū)ο蟮纳?。無(wú)名對(duì)象的生命期并不依賴于建立它的作用域,比如在函數(shù)中建立的動(dòng)態(tài)對(duì)象在函數(shù)返回后仍可使用。我們也稱堆空間為自由空間(freestore)就是這個(gè)原因。但必須記住釋放該對(duì)象所占堆空間,并只能釋放一次,在函數(shù)內(nèi)建立,而在函數(shù)外釋放是一件很容易失控的事,往往會(huì)出錯(cuò)。
第十三頁(yè),共二十三頁(yè),2022年,8月28日
堆對(duì)象與構(gòu)造函數(shù)
通過(guò)new建立的對(duì)象要調(diào)用構(gòu)造函數(shù),通過(guò)delete刪除對(duì)象也要調(diào)用析構(gòu)函數(shù)。CGoods*pc;pc=newCGoods;
//分配堆空間,并構(gòu)造一個(gè)無(wú)名的CGoods對(duì)象;…….deletepc;
//先析構(gòu),然后將內(nèi)存空間返回給堆;
堆對(duì)象的生命期并不依賴于建立它的作用域,所以除非程序結(jié)束,堆對(duì)象(無(wú)名對(duì)象)的生命期不會(huì)到期,并且需要顯式地用delete語(yǔ)句析構(gòu)堆對(duì)象,上面的堆對(duì)象在執(zhí)行delete語(yǔ)句時(shí),C++自動(dòng)調(diào)用其析構(gòu)函數(shù)。正因?yàn)闃?gòu)造函數(shù)可以有參數(shù),所以new后面類(class)類型也可以有參數(shù)。這些參數(shù)即構(gòu)造函數(shù)的參數(shù)。但對(duì)創(chuàng)建數(shù)組,則無(wú)參數(shù),并只調(diào)用缺省的構(gòu)造函數(shù)。見(jiàn)下例類說(shuō)明:第十四頁(yè),共二十三頁(yè),2022年,8月28日
堆對(duì)象與構(gòu)造函數(shù)classCGoods{charName[21];intAmount;floatPrice;floatTotal_value;public:CGoods(){};//缺省構(gòu)造函數(shù)。
//因已有構(gòu)造函數(shù),系統(tǒng)不會(huì)自動(dòng)生成,必須顯式說(shuō)明。
CGoods(char*name,intamount,floatprice){strcpy(Name,name);Amount=amount;Price=price;Total_value=price*amount;
}
……};第十五頁(yè),共二十三頁(yè),2022年,8月28日
堆對(duì)象與構(gòu)造函數(shù)下面注意如何使用:voidmain(){intn;CGoods*pc,*pc1,*pc2;pc=newCGoods(“夏利2000”,10,118000);
//調(diào)用三參數(shù)構(gòu)造函數(shù)
pc1=newCGoods();//調(diào)用缺省構(gòu)造函數(shù)
cout<<“輸入商品類數(shù)組元素?cái)?shù)”<<endl;cin>>n;pc2=newCGoods[n];
//動(dòng)態(tài)建立數(shù)組,不能初始化,調(diào)用n次缺省構(gòu)造函數(shù)
……
deletepc;deletepc1;delete[]pc2;}第十六頁(yè),共二十三頁(yè),2022年,8月28日
堆對(duì)象與構(gòu)造函數(shù)這里再次強(qiáng)調(diào):由堆區(qū)創(chuàng)建對(duì)象數(shù)組,只能調(diào)用缺省的構(gòu)造函數(shù),不能調(diào)用其他任何構(gòu)造函數(shù)。如果沒(méi)有缺省的構(gòu)造函數(shù),則不能創(chuàng)建堆區(qū)的對(duì)象數(shù)組。第十七頁(yè),共二十三頁(yè),2022年,8月28日
淺拷貝與深拷貝
缺省拷貝構(gòu)造函數(shù),可用一個(gè)類對(duì)象初始化另一個(gè)類對(duì)象,稱為缺省的按成員拷貝,而不是對(duì)整個(gè)類對(duì)象的按位拷貝。這稱為淺拷貝。
P堆對(duì)象堆對(duì)象PP
圖1淺拷貝
拷貝前拷貝后
第十八頁(yè),共二十三頁(yè),2022年,8月28日
淺拷貝與深拷貝
如果類中有一個(gè)數(shù)據(jù)成員為指針,該類的一個(gè)對(duì)象obj1中的這個(gè)指針p,指向了動(dòng)態(tài)分配的一個(gè)堆對(duì)象,(參見(jiàn)圖1拷貝前),如果用obj1按成員拷貝了一個(gè)對(duì)象obj2,這時(shí)obj2.p也指向同一個(gè)堆對(duì)象。當(dāng)析構(gòu)時(shí),如用缺省的析構(gòu)函數(shù),則動(dòng)態(tài)分配的堆對(duì)象不能回收。如果在析構(gòu)函數(shù)中有“deletep;”語(yǔ)句,則如果先析構(gòu)函數(shù)obj1時(shí),堆對(duì)象已經(jīng)釋放,以后再析構(gòu)obj2時(shí)出現(xiàn)了二次釋放的問(wèn)題。這時(shí)就要重新定義拷貝的構(gòu)造函數(shù),給每個(gè)對(duì)象獨(dú)立分配一個(gè)堆對(duì)象,稱深拷貝。這時(shí)先拷貝對(duì)象主體,再為obj2分配一個(gè)堆對(duì)象,最后用obj1的堆對(duì)象拷貝obj2的堆對(duì)象。
堆對(duì)象PP堆對(duì)象
圖2深拷貝
第十九頁(yè),共二十三頁(yè),2022年,8月28日
淺拷貝與深拷貝[例7.3]定義拷貝(copystructor)和拷貝賦值操作符(copyAssignmentOperator)實(shí)現(xiàn)深拷貝。
學(xué)生類定義:classstudent{ char*pName;//指針成員public: student(); student(char*pname); student(student&s);//拷貝構(gòu)造函數(shù)
~student(); student&operator=(student&s);//拷貝賦值操作符};缺省構(gòu)造函數(shù):student::student(){cout<<"Constructor"; pName=NULL;cout<<"缺省"<<endl;}第二十頁(yè),共二十三頁(yè),2022年,8月28日
淺拷貝與深拷貝帶參數(shù)構(gòu)造函數(shù):student::student(char*pname){cout<<"Constructor";if(pName=newchar[strlen(pname)+1])strcpy(pName,pname);cout<<pName<<endl;}拷貝構(gòu)造函數(shù):student::student(student&s){cout<<"CopyConstructor";if(s.pName){
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度汽車品牌推廣活動(dòng)策劃合同
- 2025年度出租車行業(yè)特許經(jīng)營(yíng)合同3篇
- 2025年生態(tài)園林人工草皮種植養(yǎng)護(hù)合作協(xié)議2篇
- 2025年度網(wǎng)絡(luò)安全防護(hù)服務(wù)合同范本-@-3
- 二零二五年度商業(yè)廣場(chǎng)盆景植物租賃與活動(dòng)策劃協(xié)議3篇
- 2025年度互聯(lián)網(wǎng)企業(yè)三方合伙人投資協(xié)議書(shū)3篇
- 2025年軸托行業(yè)深度研究分析報(bào)告
- 2025年初中語(yǔ)文:春晚觀后感三篇
- 2025年互動(dòng)教學(xué)系統(tǒng)項(xiàng)目投資可行性研究分析報(bào)告
- 2019-2025年中國(guó)零擔(dān)貨運(yùn)行業(yè)市場(chǎng)調(diào)研分析及投資戰(zhàn)略咨詢報(bào)告
- 慈溪高一期末數(shù)學(xué)試卷
- 天津市武清區(qū)2024-2025學(xué)年八年級(jí)(上)期末物理試卷(含解析)
- 《徐霞客傳正版》課件
- 江西硅博化工有限公司年產(chǎn)5000噸硅樹(shù)脂項(xiàng)目環(huán)境影響評(píng)價(jià)
- 高端民用航空復(fù)材智能制造交付中心項(xiàng)目環(huán)評(píng)資料環(huán)境影響
- 量子醫(yī)學(xué)成像學(xué)行業(yè)研究報(bào)告
- DB22T 3268-2021 糧食收儲(chǔ)企業(yè)安全生產(chǎn)標(biāo)準(zhǔn)化評(píng)定規(guī)范
- 辦事居間協(xié)議合同范例
- 正念減壓療法詳解課件
- GB 30254-2024高壓三相籠型異步電動(dòng)機(jī)能效限定值及能效等級(jí)
- 重大事故隱患判定標(biāo)準(zhǔn)與相關(guān)事故案例培訓(xùn)課件
評(píng)論
0/150
提交評(píng)論