2012-03-02 116 views
12

這個問題總是困擾着我,特別是當我用Qt編程時。由於Qt使用對象所有權樹,所以傳遞一個指針例如通過myBoostSharedPtr.get()可以隱式轉移所有權。 現在考慮一些Qt對象被銷燬並且整個對象樹被銷燬但智能指針仍然存在的情況,例如作爲不同班級的成員。 如果智能指針被刪除後會發生什麼? 雙重刪除與所有惡劣的後果? 做一些智能指針實現可以防止這種情況發生嗎?如果智能指針所持有的對象在別處被刪除,會發生什麼情況?

+1

我實際上遇到了'QSharedPointer'這個問題,它在概念上與boost的'shared_ptr'非常相似。我寫了一篇關於我的發現的博客文章:http://blog.codef00.com/2011/12/15/not-so-much-fun-with-qsharedpointer/ – 2012-03-03 06:13:09

回答

18

我很想嘗試一下Qt的內存模型的缺陷,其中很多API仍然接受原始指針,期望客戶端分配它,而接受指針的QObject刪除它。

您的問題的答案是未定義的行爲shared_ptr沒有檢測指針是否被shared_ptr本身以外的其他東西刪除的機制,因此它通常會嘗試第二次釋放指針(在懸掛指針上調用delete)。如果你想使用shared_ptr,你必須堅持使用shared_ptr作爲唯​​一的內存管理器。即使對於Qt自己的QSharedPointer也是如此。

我通常做嘗試使用類似Qt的時候把我的代碼相當異常安全是使用現在已經過時auto_ptrunique_ptr替換它是更安全,如果你有C++ 11可用)。這是我以前唯一使用auto_ptr的地方,因爲它提供了release方法。

unique_ptr<QListWidget> widget(new QListWidget(...)); 
// do stuff with the widget to set it up for your GUI 
some_layout.addWidget(widget.release()); // <-- release ownership so that 
             // the layout now becomes responsible 
             // for memory management 
// ^^ auto_ptr works above if we don't have C++11 

如果你需要一個持久的指針保持到您的對象後,它已經被Qt的內存管理(例如:一個指向你的widget你插入它變成一個佈局後),只需使用普通的指針。因爲Qt現在是該對象的內存管理器,所以你不能做得更好。

但是,您可以通過QObject::destroyed信號檢測對象何時被銷燬(因此當指針失效時)。

如果你想變得非常複雜,你可以建立一個只存儲QObject的子類的共享指針類型。由於QObject提供了一個被破壞的信號,這種自定義智能指針可以檢測QObject何時通過銷燬信號被銷燬,並避免再次嘗試刪除該對象。然而,它可能會在多線程代碼中依賴於這個信號而發癢,而且如果你實現了一個共享指針,它可能成爲處理原子引用計數的一個負擔,在構建指針的站點捕獲刪除函數(以避免模塊邊界新/刪除不匹配)等。

+0

我不認爲你應該在參數列表中釋放。如果'addWidget'在它接管指針之前拋出,則已經泄漏。 – GManNickG 2012-03-02 23:46:18

+1

@GmanNickG這是一個很好的觀點。你認爲我們應該在通話成功後才能放行嗎?我看它的方式,API接受客戶端分配的內存的原始指針。如果我通過了它,我們有責任在* addWidget *發生異常時調用delete指針。否則就是QT泄漏,而不是我看到的,而且文檔沒有說明QT是否試圖通過在addWidget中用本地try/catch塊刪除指針來處理這種情況。如果它確實並刪除了addWidget中的指針並重新拋出,我的unique_ptr可能會調用delete .. – stinky472 2012-03-02 23:52:42

+0

@GManNickG ...在一個懸掛指針上。這非常依賴於我對addWidget如何實現的瞭解。 – stinky472 2012-03-02 23:55:58

1

是的,最有可能和不,他們不,我不明白他們怎麼可能。你必須依靠契約,你傳遞指針的東西不會擁有所有權(除非文檔說明它),並且如果後者不包含在你身邊的智能指針中。

1

您不能在父QObject和智能指針之間共享所有權,並防止刪除另一個,但您可以僅使用QWeakPointer來跟蹤刪除任何QObject (或QPointer)。

http://qt-project.org/doc/qt-4.8/qweakpointer.html#tracking-qobject

更新:有了Qt 5,跟蹤QObject通過QSharedPointerQWeakPointer不是管理有利於QPointer已過時(它本身undeprecated)。

+0

你不應該。不使用'QSharedPointer'的'QWeakPointer'由於很好的原因而被棄用,這與它不在_C++ 11_中是一樣的。 – abergmeier 2013-06-24 11:09:17

+0

@abergmeier我不知道你爲什麼反對投票,而不是僅僅離開評論,甚至自己更新答案。在編寫本文時,推薦使用'QWeakPointer'來實現'QObject'跟蹤。 – alexisdm 2013-06-24 20:22:57

相關問題