閱讀目錄 在C語言中,我們寫程序時,總是會有動態(tài)開辟內(nèi)存的需求,每到這個時候我們就會想到用malloc/free 去從堆里面動態(tài)申請出來一段內(nèi)存給我們用。但對這一塊申請出來的內(nèi)存,往往還需要我們對它進行稍許的“加工”后即初始化 才能為我們所用,雖然C語言為我們提供了calloc來開辟一段初始化好(0)的一段內(nèi)存,但面對象中各是各樣的數(shù)據(jù)成員初始化,它同樣束手無策。同時,為了保持良好的編程習(xí)慣,我們也都應(yīng)該對申請出來的內(nèi)存作手動進行初始化。 對此,這常常讓我們感到一絲繁瑣,于是到了C 中就有了new/delete, new []/delete[] 。用它們便可實現(xiàn)動態(tài)的內(nèi)存管理。 點擊回頂部new/delete, new []/delete [] 基本格式new/delete動態(tài)管理對象,new[]/delete[]動態(tài)管理對象數(shù)組。 在C 中,把int 、char..等內(nèi)置類型的變量也看作對象,它們也是存在構(gòu)造函數(shù)和析構(gòu)函數(shù)的,只是通常對它們,系統(tǒng)調(diào)用了默認的構(gòu)造函數(shù)來初始化以及默認的析構(gòu)(編譯器優(yōu)化)。所以new int、new int(3)看起來和普通的定義好像沒什么區(qū)別。 但對于自定義類型的對象,此種方式在創(chuàng)建對象的同時,還會將對象初始化好;于是new/delete、new []/delete []方式管理內(nèi)存相對于malloc/free的方式管理的優(yōu)勢就體現(xiàn)出來了,因為它們能保證對象一被創(chuàng)建出來便被初始化,出了作用域便被自動清理。 點擊回頂部malloc/free和new/delete的區(qū)別和聯(lián)系* malloc/free只是動態(tài)分配內(nèi)存空間/釋放空間。而new/delete除了分配空間還會調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)進行初始化與清理(清理成員)。 * 它們都是動態(tài)管理內(nèi)存的入口。 * malloc/free管理內(nèi)存失敗會返回0,new/delete等的方式管理內(nèi)存失敗會拋出異常。 盡管看起來new、new[] 和malloc 都能開得空間出來,并且以new 、new[]的方式好像還更有優(yōu)勢。但從系統(tǒng)層面看來,真正開出空間來的還是malloc。為什么這么說呢? 在C Primer書中有提到說: new/delete的表達式與標(biāo)準庫函數(shù)同名了,所以系統(tǒng)并沒有重載new或delete表達式。new/delete真正的實現(xiàn)其實是依賴下面這幾個內(nèi)存管理接口的。c 中稱之為“placement版”內(nèi)存管理接口 接口原型: void * operator new (size_t size); void operator delete (size_t size); void * operator new [](size_t size); void operator delete[] (size_t size); 探究它,不妨從這樣一個類AA開始 類AA用AA* pA = new AA[10]創(chuàng)建對象,VS下通過調(diào)試進入new表達式內(nèi)部系統(tǒng)函數(shù),得到下面兩個圖: 和 通過上面兩個圖,大致可以看出來new表達式并不直接開辟內(nèi)存出來,而是通過調(diào)用operator new來獲得的內(nèi)存,而operator new獲得的內(nèi)存實質(zhì)上還是用malloc開辟出來的。這便證實了前面所述的:開空間出來還是得 malloc來。 同樣的道理,delete表達式也不是直接去釋放掉內(nèi)存。比如對上面的對象數(shù)組進行delete AA* pA = new AA[10]; delete[] pa; delete[]實際做了這樣幾件事情: * 依次調(diào)用pA指向?qū)ο髷?shù)組中每個對象的析構(gòu)函數(shù),共10次 * 調(diào)用operator delete[](),它將再調(diào)用operator delete * 底層用free執(zhí)行operator delete表達式,依次釋放內(nèi)存 綜合相關(guān)資料,小結(jié)一下operator new/ operator delete: 1.operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一樣。 如果仔細看過上面的圖,可能會有疑惑:new最后將開辟好內(nèi)存用指針p返回,pA接收它??蔀槭裁磒 和pA 會差上4字節(jié)? 這其實是因為編譯器用相差的這4個字節(jié)用來保存一個東西——對象個數(shù),即AA* p = new AA[10] 中的‘10’。這也就不難解釋 為什么在delete[] 的時候,不用傳給它對象個數(shù)。
delete[] 刪除時,將new[] 返回的地址再往前移4個字節(jié)便可以拿到要析構(gòu)的對象個數(shù)了。 但是注意:new type[] ,只有type顯示定義析構(gòu)函數(shù)時,編譯器才會多開4字節(jié)來保存對象個數(shù)。所以像new int、char這樣的內(nèi)置類型編譯器不會多開這4字節(jié),編譯器自行優(yōu)化。 它們之間可用下面的圖展示: 點擊回頂部new/delete, new []/delete[], malloc/free配套使用!我們new 出來多少個對象,就得調(diào)用多少次析構(gòu)來對它們進行清理。在用new/delete,new[]/delete[], malloc/free進行內(nèi)存的管理時,一定不能將它們搞混淆,使用它們一定記得配套使用。 來看幾個例子,還是以前面AA類為例 類AA1.malloc/delete的組合 void Test1() { AA* p1 = (AA*)malloc(sizeof(AA)); //沒有報錯,但不建議采用,容易引起混淆 delete p1; AA* p2 = (AA*)malloc(sizeof(AA)); //報錯,同上,釋放位置也不對 delete[] p2; } 2.delete, delete[] 之間誤用(值得注意) void Test2() { AA* p3 = new AA; //不報錯,但未清理干凈。p3的構(gòu)造函數(shù)開辟的空間沒有被釋放 free(p3); AA* p4 = new AA[10]; //崩潰卡死,存在問題,釋放位置被后移了4字節(jié)。同時只調(diào)用了一次析構(gòu)函數(shù)
3.針對內(nèi)置類型 void Test3() { int* p6 = new int[10]; //沒問題 delete[] p6; int* p7 = new int[10]; //沒問題 delete p7; int* p8 = new int[10]; //沒問題 free(p8); } 內(nèi)存管理內(nèi)置類型,它們的析構(gòu)函數(shù)其實上是可調(diào)可不調(diào)的,所以它的實現(xiàn)機制不像前面的new []/delete[],編譯器會自行對處理的數(shù)據(jù)做記錄,然后處理;所以即便是不匹配的使用,它們也沒出現(xiàn)什么問題。不僅僅這種內(nèi)置類型如此,那種無自定義類型析構(gòu)函數(shù)的類對象,這樣的用法同樣不會表現(xiàn)出什么問題。但即便如此,為保存良好的編程習(xí)慣,還是要配對地使用它們! 結(jié)合前面new/delete 的實現(xiàn)機制,便不難分析得出它們?nèi)粑磁鋵κ褂每赡艹霈F(xiàn)的情況。 總的來說,記住一點即可:new/delete、new[]/delete[] 配套使用總是沒錯的! 來源:https://www./content-3-721951.html |
|