C++ delete this

delete this 的使用及注意事項(xiàng)

    1. this對(duì)象是必須是用 new操作符分配的(而不是用new[]产阱,也不是用placement new苹粟,也不是局部對(duì)象,也不是global對(duì)象)耻台;
    1. delete this后诚欠,不能訪問該對(duì)象任何的成員變量及虛函數(shù)(delete this回收的是數(shù)據(jù),這包括對(duì)象的數(shù)據(jù)成員以及vtable草丧,不包括函數(shù)代碼)狸臣;
    1. delete this后,不能再訪問this指針昌执。換句話說烛亦,你不能去檢查它、將它和其他指針比較懂拾、和 NULL比較煤禽、打印它、轉(zhuǎn)換它岖赋,以及其它的任何事情檬果;

個(gè)人認(rèn)為保證以上禁忌列表基本手段可以包括:

    1. 將析構(gòu)函數(shù)私有化(如果有子類,則protected化贾节,保證子類能夠正確繼承)--以保證對(duì)象必須使用new在堆上分配內(nèi)存汁汗;
    1. 提供(可以在僅僅在基類中)Destroy(void)函數(shù),里面僅有一句delete this--以保證第三方能夠?qū)⒎峙涞膬?nèi)存回收栗涂;

比如你new了一個(gè)對(duì)象實(shí)例知牌,然后使用者需要調(diào)用對(duì)象里的一個(gè)服務(wù)函數(shù),想服務(wù)函數(shù)結(jié)束后就不再需要對(duì)象實(shí)例了斤程,也就是說可以刪除了角寸,那么我們就可以通過在函數(shù)最后調(diào)用delete this將自己刪除,也就是傳說中的“自殺”忿墅。
但為什么能自殺呢扁藕,我個(gè)人簡單的理解就是類成員函數(shù)是真實(shí)存在的,不管你實(shí)例是否存在疚脐,只不過如果沒有實(shí)例的話亿柑,類成員函數(shù)中的this指針就不存在了,所以這也是平時(shí)我們不能隨意調(diào)用類成員函數(shù)的原因棍弄,那么當(dāng)我們調(diào)用delete this時(shí)望薄,他刪除了對(duì)象自己,但我們的程序依然跑在那個(gè)成員函數(shù)的代碼中呼畸,只要delete this后面沒有什么數(shù)據(jù)是依賴于this指針的話也就不會(huì)出現(xiàn)問題了痕支。
當(dāng)然這里有個(gè)例外的地方,就是不能在析構(gòu)函數(shù)里調(diào)用delete this蛮原,否則就會(huì)進(jìn)入死循環(huán)了卧须。。。花嘶。笋籽。(這個(gè)你懂的,我不說了)

delete 執(zhí)行了哪些步驟察绷?

在對(duì)類指針使用delete時(shí)干签,實(shí)際發(fā)生了兩個(gè)步驟。
A:先是調(diào)用該類的析構(gòu)函數(shù)拆撼,以做數(shù)據(jù)成員的釋放工作容劳,以及一些finish code,這一切由程序員自己定義闸度。
B:然后再調(diào)用operator delete(void*)釋放該對(duì)象實(shí)例的內(nèi)存數(shù)據(jù)竭贩。這是一個(gè)對(duì)象在消亡之前的所做的最后動(dòng)作。一般不要override這個(gè)函數(shù)莺禁,如果要留量,務(wù)必記住最后調(diào)用系統(tǒng)的::operator delete真正釋放該對(duì)象所占用的內(nèi)存。
一般來說哟冬,內(nèi)存釋放釋放的只能是數(shù)據(jù)段的內(nèi)容(包括堆和棧楼熄,但釋放棧上的內(nèi)存由系統(tǒng)進(jìn)行),而代碼段的內(nèi)存浩峡,除一些病毒攻擊等非正常強(qiáng)行改寫手段外可岂,在內(nèi)存中是永遠(yuǎn)不會(huì)釋放/改變的,直到程序結(jié)束翰灾,因此在內(nèi)存釋放后也是可以訪問的缕粹。所以,一般所謂的釋放內(nèi)存delete操作纸淮,是在數(shù)據(jù)段進(jìn)行的釋放平斩。

delete原語看起來會(huì)是如下的樣子:
p->~object();
object::operator delete(p);
因?yàn)榇a段的內(nèi)存是不會(huì)被釋放的,因此無論對(duì)象p的內(nèi)存有沒有釋放咽块,這兩個(gè)語句都會(huì)執(zhí)行绘面,不會(huì)因?yàn)閜沒有指向任何存在的對(duì)象而報(bào)錯(cuò),只是在最后執(zhí)行到::operator delete的時(shí)候侈沪,才會(huì)在執(zhí)行_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse))的時(shí)候報(bào)錯(cuò)飒货。

在類的成員函數(shù)中調(diào)用delete this

在類的成員函數(shù)中能不能調(diào)用delete this?答案是肯定的峭竣,能調(diào)用,而且很多老一點(diǎn)的庫都有這種代碼晃虫。假設(shè)這個(gè)成員函數(shù)名字叫release皆撩,而delete this就在這個(gè)release方法中被調(diào)用,那么這個(gè)對(duì)象在調(diào)用release方法后,還能進(jìn)行其他操作扛吞,如調(diào)用該對(duì)象的其他方法么呻惕?答案仍然是肯定 的,調(diào)用release之后還能調(diào)用其他的方法滥比,但是有個(gè)前提:被調(diào)用的方法不涉及這個(gè)對(duì)象的數(shù)據(jù)成員和虛函數(shù)亚脆。說到這里,相信大家都能明白為什么會(huì)這樣 了盲泛。

根本原因在于delete操作符的功能和類對(duì)象的內(nèi)存模型濒持。當(dāng)一個(gè)類對(duì)象聲明時(shí),系統(tǒng)會(huì)為其分配內(nèi)存空間寺滚。在類對(duì)象的內(nèi)存空間中柑营,只有數(shù)據(jù)成員和虛函數(shù)表指針,并不包含代碼內(nèi)容村视,類的成員函數(shù)單獨(dú)放在代碼段中官套。在調(diào)用成員函數(shù)時(shí),隱含傳遞一個(gè)this指針蚁孔,讓成員函數(shù)知道當(dāng)前是哪個(gè)對(duì)象在調(diào)用它奶赔。當(dāng) 調(diào)用delete this時(shí),類對(duì)象的內(nèi)存空間被釋放杠氢。在delete this之后進(jìn)行的其他任何函數(shù)調(diào)用站刑,只要不涉及到this指針的內(nèi)容,都能夠正常運(yùn)行修然。一旦涉及到this指針笛钝,如操作數(shù)據(jù)成員,調(diào)用虛函數(shù)等愕宋,就會(huì)出現(xiàn)不可預(yù)期的問題玻靡。

為什么是不可預(yù)期的問題?delete this之后不是釋放了類對(duì)象的內(nèi)存空間了么中贝,那么這段內(nèi)存應(yīng)該已經(jīng)還給系統(tǒng)囤捻,不再屬于這個(gè)進(jìn)程。照這個(gè)邏輯來看邻寿,應(yīng)該發(fā)生指針錯(cuò)誤蝎土,無訪問權(quán)限之類的令系統(tǒng)崩潰的問題才對(duì)啊绣否?這個(gè)問題牽涉到操作系統(tǒng)的內(nèi)存管理策略誊涯。delete this釋放了類對(duì)象的內(nèi)存空間,但是內(nèi)存空間卻并不是馬上被回收到系統(tǒng)中蒜撮,可能是緩沖或者其他什么原因暴构,導(dǎo)致這段內(nèi)存空間暫時(shí)并沒有被系統(tǒng)收回跪呈。此時(shí)這段內(nèi)存是可以訪問的,你可以加上100取逾,加上200耗绿,但是其中的值卻是不確定的。當(dāng)你獲取數(shù)據(jù)成員砾隅,可能得到的是一串很長的未初始化的隨機(jī)數(shù)误阻;訪問虛函數(shù)表,指針無效的可能性非常高晴埂,造成系統(tǒng)崩潰究反。

大致明白在成員函數(shù)中調(diào)用delete this會(huì)發(fā)生什么之后,再來看看另一個(gè)問題邑时,如果在類的析構(gòu)函數(shù)中調(diào)用delete this奴紧,會(huì)發(fā)生什么?實(shí)驗(yàn)告訴我們晶丘,會(huì)導(dǎo)致堆棧溢出黍氮。原因很簡單,delete的本質(zhì)是“為將被釋放的內(nèi)存調(diào)用一個(gè)或多個(gè)析構(gòu)函數(shù)浅浮,然后沫浆,釋放內(nèi)存” (來自effective c++)。顯然滚秩,delete this會(huì)去調(diào)用本對(duì)象的析構(gòu)函數(shù)专执,而析構(gòu)函數(shù)中又調(diào)用delete this,形成無限遞歸郁油,造成堆棧溢出本股,系統(tǒng)崩潰

上面是某大牛的分析桐腌,而在實(shí)際的運(yùn)行過程中使用delele this確實(shí)會(huì)直接出現(xiàn)錯(cuò)誤拄显。這是因?yàn)椋涸诔蓡T函數(shù)中調(diào)用delete this,首先會(huì)調(diào)用類的析構(gòu)函數(shù)案站,this指針已刪除躬审,會(huì)出現(xiàn)指針錯(cuò)誤。

下面是在XCode中使用delete this出現(xiàn)的錯(cuò)誤:

malloc: *** error for object 0xbffffa18: pointer being freed was not allocated

//注意0xbffffa18即為this的地址
*** set a breakpoint in malloc_error_break to debug

而在VS2010中使用delete this是直接導(dǎo)致 Debug Assertion Failed蟆盐!

具體的描述是:invalid null pointer

總結(jié):在成員函數(shù)中調(diào)用delete this承边,會(huì)導(dǎo)致指針錯(cuò)誤,而在析構(gòu)函數(shù)中調(diào)用delete this石挂,出導(dǎo)致死循環(huán)博助,造成堆棧溢出。

PS:this是類中成員函數(shù)具有的一個(gè)附加的隱含形參痹愚,即指向該類對(duì)象的一個(gè)指針富岳,它與調(diào)用成員函數(shù)的對(duì)象綁定在一起罗心。同時(shí)1.在普通的非const成員函數(shù)中:this的類型是一個(gè)指向類類型的const指針,可以改變this指向的值城瞎,但是不能改變this所保存的地址;2.在const成員函數(shù)中疾瓮,this的類型是一個(gè)指向const類類型對(duì)象的const指針脖镀,既不能改變this所指向的對(duì)象,也不能改變this所保存的地址狼电。

注意:

  1. 成員函數(shù)中不能定義this形參蜒灰,而是由編譯器隱含地定義,但是可以在成員函數(shù)中顯示使用this形參肩碟,不過也不是必須這么做强窖。如果對(duì)類成員的引用沒有限定,編譯器會(huì)將這種引用處理成通過this指針的引用削祈。
  2. 有一種情況下必須顯式使用this:當(dāng)我們需要將一個(gè)對(duì)象作為整體引用而不是引用對(duì)象的一個(gè)成員時(shí)翅溺。
  3. 從const成員函數(shù)返回*this:不能從const成員函數(shù)返回指向類對(duì)象的普通引用。const成員函數(shù)只能返回*this作為一個(gè)const引用髓抑。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末咙崎,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吨拍,更是在濱河造成了極大的恐慌褪猛,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件羹饰,死亡現(xiàn)場離奇詭異伊滋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)队秩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門笑旺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人刹碾,你說我怎么就攤上這事燥撞。” “怎么了迷帜?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵物舒,是天一觀的道長。 經(jīng)常有香客問我戏锹,道長冠胯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任锦针,我火速辦了婚禮荠察,結(jié)果婚禮上置蜀,老公的妹妹穿的比我還像新娘。我一直安慰自己悉盆,他們只是感情好盯荤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著焕盟,像睡著了一般秋秤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脚翘,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天灼卢,我揣著相機(jī)與錄音,去河邊找鬼来农。 笑死鞋真,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沃于。 我是一名探鬼主播涩咖,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼揽涮!你這毒婦竟也來了抠藕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤蒋困,失蹤者是張志新(化名)和其女友劉穎盾似,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雪标,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡零院,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了村刨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片告抄。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖嵌牺,靈堂內(nèi)的尸體忽然破棺而出打洼,到底是詐尸還是另有隱情,我是刑警寧澤逆粹,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布募疮,位于F島的核電站,受9級(jí)特大地震影響僻弹,放射性物質(zhì)發(fā)生泄漏阿浓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一蹋绽、第九天 我趴在偏房一處隱蔽的房頂上張望芭毙。 院中可真熱鬧筋蓖,春花似錦、人聲如沸退敦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侈百。三九已至涂炎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間设哗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國打工两蟀, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留网梢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓赂毯,卻偏偏與公主長得像战虏,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子党涕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容