一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

深入理解C new/delete, new []/delete[]動態(tài)內(nèi)存管理(轉(zhuǎn))

 印度阿三17 2020-07-20

閱讀目錄

在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是C/C 標(biāo)準庫的函數(shù),new/delete是C 操作符。
  *  malloc/free需要手動計算類型大小且返回值w為void*,new/delete可自動計算類型的大小,返回對應(yīng)類型的指針。

  *  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用法一樣。
   2. 他們只負責(zé)分配空間/釋放空間,不會調(diào)用對象構(gòu)造函數(shù)/析構(gòu)函數(shù)來初始化/清理對象。
   3. 實際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類為例

 類AA

1.malloc/delete的組合

復(fù)制代碼
void Test1()
{

    AA* p1 = (AA*)malloc(sizeof(AA));   //沒有報錯,但不建議采用,容易引起混淆
    delete p1;                       
    AA* p2 = (AA*)malloc(sizeof(AA));   //報錯,同上,釋放位置也不對
    delete[] p2;
}
復(fù)制代碼

2.delete, delete[] 之間誤用(值得注意)

復(fù)制代碼
void Test2()
{
    AA* p3 = new AA;         //不報錯,但未清理干凈。p3的構(gòu)造函數(shù)開辟的空間沒有被釋放
    free(p3);
    AA* p4 = new AA[10];   //崩潰卡死,存在問題,釋放位置被后移了4字節(jié)。同時只調(diào)用了一次析構(gòu)函數(shù)
   delete p4; ,
   AA* p5 = new AA; //報錯 非法訪問內(nèi)存
   delete[] p5;
}

①delete p4錯誤在于釋放位置不對(和編譯器實現(xiàn)new []的機制有關(guān)),導(dǎo)致內(nèi)存泄漏



②delete[] p5 直接就崩了,這次new AA的時候并未多開4字節(jié)保存對象個數(shù),編譯器便無法知道要調(diào)用多少次析構(gòu)函數(shù)(這里僅僅調(diào)用一次析構(gòu)函數(shù)就好了)但編譯器內(nèi)部還是試圖去訪問p5前4字節(jié)的內(nèi)存,以此獲得對象個數(shù);這便非法內(nèi)存訪問了,所以程序就掛了。
復(fù)制代碼

3.針對內(nèi)置類型

復(fù)制代碼
void Test3()
{
    int* p6 = new int[10];  //沒問題
    delete[] p6;
    int* p7 = new int[10];  //沒問題
    delete p7;
    int* p8 = new int[10];  //沒問題
    free(p8);
           
}
復(fù)制代碼
內(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

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    99热在线播放免费观看| 男人操女人下面国产剧情| 欧美一区二区日韩一区二区| 在线亚洲成人中文字幕高清 | 国产精品久久精品毛片| 国产传媒精品视频一区| 欧美一区二区三区喷汁尤物| 中文字幕精品少妇人妻| 日本办公室三级在线观看| 激情三级在线观看视频| 黄色美女日本的美女日人| 欧美成人精品一区二区久久| 国产亚洲欧美自拍中文自拍| 久久国产精品亚州精品毛片| 亚洲欧美日韩国产自拍| 日韩精品少妇人妻一区二区| 激情偷拍一区二区三区视频| 亚洲日本加勒比在线播放| 亚洲最新中文字幕一区| 亚洲欧美国产中文色妇| 黑人粗大一区二区三区| 亚洲国产av精品一区二区| 国产精品一区二区三区日韩av| 91久久国产福利自产拍| 亚洲精选91福利在线观看| 国产欧洲亚洲日产一区二区| 午夜久久精品福利视频| 蜜桃av人妻精品一区二区三区| 欧美成人黄色一级视频| 富婆又大又白又丰满又紧又硬| 日本欧美三级中文字幕| 五月天婷亚洲天婷综合网| 亚洲一区二区三区av高清| 日韩少妇人妻中文字幕| 中文字幕禁断介一区二区| 少妇熟女精品一区二区三区| 欧美午夜视频免费观看| 好吊色欧美一区二区三区顽频| 中文字字幕在线中文乱码二区| 久久中文字幕中文字幕中文| 国产视频福利一区二区|