2013-02-14 32 views
5

我有一個對象,裏面有一些指針。析構函數在這些指針上調用delete。但有時我想刪除它們,有時我不會。所以我希望能夠刪除對象而不用調用析構函數。這可能嗎?是否有可能在不調用析構函數的情況下刪除C++中的對象?

編輯:我意識到這是一個很好的想法,沒有人應該做。不過,我想這樣做,因爲它會使一些內部函數更容易編寫。

+0

所以問題是如何使動態分配的對象以不需要顯式調用'delete' /'free'的方式釋放? – LihO 2013-02-14 18:07:53

+0

@LihO是的。或者,在不調用析構函數的情況下調用'delete' /'free'。 – 2013-02-14 18:10:25

+5

那麼,只需將這些內部指針設置爲'nullptr',然後'刪除它們將是一個空操作。 – 2013-02-14 18:10:52

回答

7

您可以將指針設置爲NULL,那麼析構函數將不會刪除它們。

struct WithPointers 
{ 
    int* ptr1; 
    int* ptr2; 

    WithPointers(): ptr1(NULL), ptr2(NULL) {} 

    ~WithPointers() 
    { 
     delete ptr1; 
     delete ptr2; 
    } 
} 

... 
WithPointers* object1 = new WithPointers; 
WithPointers* object2 = new WithPointers; 
object1->ptr1 = new int(11); 
object1->ptr2 = new int(12); 
object2->ptr1 = new int(999); 
object2->ptr2 = new int(22); 
... 
int* pointer_to_999 = object2->ptr1; 
object2->ptr1 = NULL; 
delete object1; 
delete object2; // the number 999 is not deleted now! 
// Work with the number 999 
delete pointer_to_999; // please remember to delete it at the end! 
+0

它忘記了未來的繁榮。使用武力,並提防黑暗! – 2013-02-14 18:14:16

+0

我應該想到這個簡單的伎倆。謝謝。 – 2013-02-14 18:58:19

+1

@MichaelDorgan:如果他忘記了它並不是一個問題,那麼它會變得繁榮:他會發現它並糾正它。 「黑暗的一面」是不正確的東西,但不要繁榮! (你永遠不會知道,直到用戶有一天會看到不正確的東西) – 2013-02-14 20:08:16

4

Eww!是的,這是可能的,不,我不會這樣做。通過共享指針或其他引用計數對象來控制需要變量生存期的對象。使用C++的清潔工比打破其內部租戶的一些清潔工...

+0

我知道這是做到這一點的正確方法,但我想以各種理由按我的方式去做。這不是公開暴露的功能,而是內部使用的一些功能,使得幾個功能更簡單。 – 2013-02-14 18:07:23

+2

我建議你不要去那裏。誰知道,在未來,其他人會走進你的代碼,並推動一些東西和繁榮。或者也許是一個新的編譯器版本等。違反規則使得很難調試某些東西,因爲在查看代碼時,解決方案不會成爲頭20件事情。 – 2013-02-14 18:11:36

+2

它可能會使某些內部函數「易於編寫」(有爭議),但它*當然*不會使它們更安全或更容易*維護*。任何人在你認爲你瘋了之後看着這段代碼。 – meagar 2013-02-14 18:18:10

2

無論你真的想要做什麼,你的代碼都有問題。 如果您不想刪除子對象,只需使用布爾標誌,您將在刪除對象之前設置該標誌,並且析構函數會將其考慮在內。

但說實話,你應該使用智能指針而不是裸指針(在你的情況下,它看起來像共享指針是你所需要的)。

1

正如其他人所說的,解決這個問題的正確方法不是調用析構函數[你只需要在對象中添加諸如std::stringstd::vector之類的內容,並且突然間你有內存泄漏] 。正確的方法是讓對象根本不擁有這些其他對象(例如,在對象被刪除之前/之後單獨刪除它們),或者讓對象知道是否刪除指針。

2

編寫一個在調用析構函數之前可以調用的方法。該方法將翻轉成員布爾值。當調用destuctor時,它將檢查該布爾成員,並在指針爲真時銷燬指針,如果該指針爲false,則保留該指針。

我不會推薦這樣做。最好不要爲刪除指針負責。

1

是的,這是可能的。 std::vector是這樣做的,因爲它爲緩衝區分配了緩衝空間,然後有條件地構造緩衝區(in-place)並銷燬它們,獨立於對象生命週期管理內存。在C++ 11中,我會使用您的類型的union和一個帶有簡單的構造函數/析構函數的小類型來指示一個可以適合您的類型的內存位置,但不必在其中包含該類型。外在的,你必須跟蹤對象是否真的存在。創建項目包括使用放置new,並銷燬它包括手動調用析構函數。

union對象的緩衝區,無論是N個對象還是1個,都將完全獨立管理。 union的默認構造函數將構造任何東西,或構造平凡類型(在這種情況下,您可能想要銷燬該平凡類型)。

但是,您的問題的真正答案是「不要這樣做」。如果你這樣做,你將指針包裝在class只有工作正在處理上述混亂。該類型的類(其作用是管理指針的生命期和指針狀屬性)稱爲「智能指針」。

7

delete運營商做了兩件事對象傳遞給它:

  • 調用適當的析構函數。
  • 調用釋放函數operator delete

所以刪除對象,而不調用析構函數意味着你要簡單地調用operator delete的對象:

Foo *f = new Foo; 
operator delete(f); 

operator delete是一個正常的函數調用和通常的名稱查找和重載解析完成。但delete運營商有其自己的規則找到正確的operator delete。例如,delete運算符將查找會員operator delete通用名稱查找和重載解析無法找到的函數。這意味着當您手動使用operator delete時,您需要確保您正在調用正確的功能。

正如你所說,直接使用operator delete是一個可怕的想法。未能調用析構函數會中斷RAII,導致資源泄漏。它甚至可能導致未定義的行爲。此外,您必須承擔編寫異常安全代碼而不使用RAII的責任,這非常困難。你幾乎可以保證弄錯了。

+0

'delete f'實際上是'f->〜Foo();運算符delete(f);'(就像'new Foo'實際上'new(operator new(sizeof(Foo)))Foo')。那些「*從構造/銷燬*中脫離分配/釋放」的形式很少見,但是當內存的歷史不遵循它所持有的對象的歷史時會發生。這通常是在例如std :: vector實現中找到的。 – 2013-02-15 08:42:17

+0

@EmilioGaravaglia我相信你只是重複我所說的一部分。我沒有看到你提出的更正,如果有的話。 – bames53 2013-02-15 15:16:11

+0

這不是一個修正:只是關於相應的放置new/operator new的補充,關於這個構造經常在標準庫內部發生 – 2013-02-15 15:21:49

相關問題