2011-06-14 109 views
16

可能重複:
Is it safe to delete this?「刪除這個」是一個壞主意嗎?

我一直在做關於它的設計作爲一個鏈表節點的類一點點工作,我想我會放棄該類自己的刪除功能與管理類相反。所以基本上是這樣的:

void Class::Delete() { 
    //Some cleanup code before deleting the object 
    delete this; 
} 

現在我測試過這一點,它看起來做工精細,但我已經在過去那裏的對象一直在運行的代碼中間的問題,被刪除,然後通過嘗試使用不再存在的對象明顯地崩潰了該程序。

由於「刪除這個」在函數的末尾是正確的,它顯然會退出函數並且工作正常,但是這種做法是不是一個壞主意?如果我不小心,這可能會在我的臉上炸開嗎?

+0

可以這樣做,但正如你之前發現的那樣做並不一定安全。你不能與對象交互了。對運行然後自行死亡的線程對象有意義。如果什麼都沒有提到他們可能是好的。 – Matt 2011-06-14 05:21:52

回答

21

FAQlite回答了這個相當不錯:

只要你小心,它是 對象確定自殺(刪除 這一點)。

這裏是我如何定義「小心」:

  1. 你必須100%的確定,this對象是用新的(不是用new []分配 ,也不 通過放置新的,也不是一個地方對象 在堆棧上,也不是全局對象,也不是另一個對象的成員;但是普通的新對象是普通的 )。
  2. 您必須絕對100%肯定您的成員 函數將成爲此對象上調用的最後一個成員 函數。
  3. 你必須100%的確定,該 成員函數的其餘部分(後刪除此 線)不接觸任何一塊本 對象(包括調用任何其他 成員函數或任何數據 成員)。
  4. 你一定絕對100%肯定沒有人接觸 這個指針本身後 刪除這一行。換句話說,你 一定不能檢查它,將它與另一個指針 比較,將它與NULL比較, 打印它,投它,用 做任何事情吧。

當然平時的告誡: 情況下,你的這個指針是 指向基類的時候你不在 有虛析構函數。

基本上,您需要像對待任何其他指針一樣謹慎。然而,與明確聲明的指針相比,成員函數實施自殺會導致更多的問題出現。

+2

我很好奇..爲什麼#4?打印指針等根本不訪問底層內存。 – ThiefMaster 2011-06-14 06:09:01

+1

出於好奇,爲什麼在刪除這個之後不要讀取'this'的值呢?在我看來,在任何情況下,這都是一個普通的刪除,在此之後允許閱讀(儘管當然沒有用處)。在標準中是明確禁止的,還是FAQ稍微過於謹慎? – 2011-06-14 06:10:23

+1

「如果刪除運算符的操作數是可修改的l值,則在刪除該對象後,其值不確定。」 - http://msdn.microsoft.com/en-us/library/h6227113.aspx – 2011-06-14 06:13:39

1

有這樣做,不涉及未定義行爲同樣的事情的一個簡單的方法:

void Class::Delete() { 
    //Some cleanup code before deleting the object 
    std::auto_ptr delete_me(this); 
} 
+2

這和'delete this'有什麼不同?我看不到'auto_ptr'會如何歸結爲任何東西,只是'刪除這個',因此對於vanilla實現沒有任何優勢。我錯了嗎? – larsmoa 2011-06-14 06:28:03

+1

這不回答這個問題。壞。 – Nawaz 2011-06-14 06:42:01

+1

這樣做的唯一的事情就是添加混淆。 – 2011-06-14 08:10:15

5

使用delete this是一個壞主意,如果一個人不知道的陷阱&他們周圍的工作。

一旦你調用delete this對象的析構函數將被調用,動態分配的內存將被釋放。

如果使用new未分配對象,它將是Undefined behaviour
如果在delete this之後訪問任何對象的數據成員或虛擬函數,則行爲將再次爲Undefined Behavior

也許,最好避免delete this給出上述。

+0

這根本就是錯的。或者說,它適用於所有使用'delete'的情況。 '刪除這個'沒有什麼特別之處。 – 2011-06-14 08:09:17

2

在C++中這樣做的習慣做法是將清理代碼放入析構函數中,然後在刪除對象時自動調用它。

Class::~Class() { 
    do_cleanup(); 
} 

void ManagingClass::deleteNode(Class* instance) { 
    delete instance; //here the destructor gets called and memory gets freed 
} 
+0

這與這個問題有什麼關係?清理代碼在析構函數中。問題是誰調用析構函數(通過'delete')。 – 2011-06-14 08:11:08

+0

@James:在問題中,'Class :: Delete'中有一些清理代碼。它在評論中這樣說:「//刪除對象之前的一些清理代碼」。我認爲有必要質疑爲什麼只有在調用'Delete'時需要清除*,而不是用於銷燬'Class'類型的對象。當然,只要有一個很好的理由就沒有問題。 – 2011-06-14 09:35:16

+0

@Steve Jessop這取決於「刪除」功能的功能;這只是一個例子。在現實生活中,不是'Delete',而是'HandleEventX',或者類似的東西,它將是唯一一個將被調用的地方。大多數時候;關於一般原則,你是對的:任何代碼,無論屬於析構函數還是屬於調用delete的函數,都必須在對象被析構時調用。 – 2011-06-14 10:56:20

4

這實際上是一種常見的習慣用法,並且與任何刪除操作一樣安全。由於 與所有刪除,您必須確保沒有進一步的代碼嘗試 訪問該對象,並且您必須確保該對象是動態分配的 。然而,通常情況下,後者不是 問題,因爲該習語僅與具有由對象的語義確定的生命週期的對象相關,並且總是動態地分配這樣的對象 。查找所有指針也是 對象可能是一個問題(是否使用delete this);通常, 某些形式的觀察者模式將被用於通知所有感興趣的對象將不再存在的所有對象 。

+1

+1更好的答案。 – Nawaz 2011-06-14 09:21:52

+0

我同意納瓦茲。 (當前)最佳答案回答了一個不同的問題,即「什麼時候刪除它是安全的?」,這與「好吧,我可以做到這一點,只要我遵守某些規則,但這是一個好主意,或者這是否意味着我可能會做出其他錯誤?「,這是一個更有趣的問題。 – allyourcode 2014-07-18 08:35:48

相關問題