這個問題總是困擾着我,特別是當我用Qt編程時。由於Qt使用對象所有權樹,所以傳遞一個指針例如通過myBoostSharedPtr.get()
可以隱式轉移所有權。 現在考慮一些Qt對象被銷燬並且整個對象樹被銷燬但智能指針仍然存在的情況,例如作爲不同班級的成員。 如果智能指針被刪除後會發生什麼? 雙重刪除與所有惡劣的後果? 做一些智能指針實現可以防止這種情況發生嗎?如果智能指針所持有的對象在別處被刪除,會發生什麼情況?
回答
我很想嘗試一下Qt的內存模型的缺陷,其中很多API仍然接受原始指針,期望客戶端分配它,而接受指針的QObject刪除它。
您的問題的答案是未定義的行爲。 shared_ptr
沒有檢測指針是否被shared_ptr本身以外的其他東西刪除的機制,因此它通常會嘗試第二次釋放指針(在懸掛指針上調用delete)。如果你想使用shared_ptr,你必須堅持使用shared_ptr作爲唯一的內存管理器。即使對於Qt自己的QSharedPointer
也是如此。
我通常做嘗試使用類似Qt的時候把我的代碼相當異常安全是使用現在已經過時auto_ptr
(unique_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何時通過銷燬信號被銷燬,並避免再次嘗試刪除該對象。然而,它可能會在多線程代碼中依賴於這個信號而發癢,而且如果你實現了一個共享指針,它可能成爲處理原子引用計數的一個負擔,在構建指針的站點捕獲刪除函數(以避免模塊邊界新/刪除不匹配)等。
我不認爲你應該在參數列表中釋放。如果'addWidget'在它接管指針之前拋出,則已經泄漏。 – GManNickG 2012-03-02 23:46:18
@GmanNickG這是一個很好的觀點。你認爲我們應該在通話成功後才能放行嗎?我看它的方式,API接受客戶端分配的內存的原始指針。如果我通過了它,我們有責任在* addWidget *發生異常時調用delete指針。否則就是QT泄漏,而不是我看到的,而且文檔沒有說明QT是否試圖通過在addWidget中用本地try/catch塊刪除指針來處理這種情況。如果它確實並刪除了addWidget中的指針並重新拋出,我的unique_ptr可能會調用delete .. – stinky472 2012-03-02 23:52:42
@GManNickG ...在一個懸掛指針上。這非常依賴於我對addWidget如何實現的瞭解。 – stinky472 2012-03-02 23:55:58
是的,最有可能和不,他們不,我不明白他們怎麼可能。你必須依靠契約,你傳遞指針的東西不會擁有所有權(除非文檔說明它),並且如果後者不包含在你身邊的智能指針中。
您不能在父QObject和智能指針之間共享所有權,並防止刪除另一個,但您可以僅使用QWeakPointer
來跟蹤刪除任何QObject
(或QPointer
)。
見http://qt-project.org/doc/qt-4.8/qweakpointer.html#tracking-qobject
更新:有了Qt 5,跟蹤QObject
通過QSharedPointer
與QWeakPointer
不是管理有利於QPointer
已過時(它本身undeprecated)。
你不應該。不使用'QSharedPointer'的'QWeakPointer'由於很好的原因而被棄用,這與它不在_C++ 11_中是一樣的。 – abergmeier 2013-06-24 11:09:17
@abergmeier我不知道你爲什麼反對投票,而不是僅僅離開評論,甚至自己更新答案。在編寫本文時,推薦使用'QWeakPointer'來實現'QObject'跟蹤。 – alexisdm 2013-06-24 20:22:57
- 1. TFS - 如果我刪除工作區會發生什麼情況?
- 2. 當所有對象引用被刪除時異步方法會發生什麼?
- 3. 如果引用的對象被刪除,引用變量會發生什麼?
- 4. 如果瀏覽器不支持gzip,會發生什麼情況?
- 5. 如果我不指定targetFramework =「4.0」,會發生什麼情況?
- 6. 如果DTD鏈接無處可逃,會發生什麼情況?
- 7. 在被刪除的對象內動態分配對象會發生什麼?
- 8. 如果我們在增加指針後刪除數組會發生什麼?
- 9. 如果刪除+和++運算符之間的空格,會發生什麼情況?
- 10. 如果在Application_Start中引發未處理的異常,會發生什麼情況?
- 11. 如果我的程序退出時無法刪除頂點緩衝區對象,會發生什麼情況?
- 12. 如果您嘗試釋放已釋放的對象,會發生什麼情況?
- 13. 如果我更改HashSet中的對象,會發生什麼情況?
- 14. 如果我刪除了所有與vBulletin相關的文件,會發生什麼情況?
- 15. 如果我釋放對象,釋放對象所屬的池後會發生什麼情況?
- 16. 如果我的IExceptionPublisher引發異常,會發生什麼情況?
- 17. 如果正在處理的活套正在退出,會發生什麼情況?
- 18. 如果一個班級有多個類別,會發生什麼情況?
- 19. ,對象和指向對象的指針有什麼區別?
- 20. 如果用正在運行的pthread刪除一個對象會發生什麼?
- 21. 如果我刪除了其他人正在處理的遠程分支,會發生什麼情況?
- 22. (C++)堆上沒有指向它們的指針的對象會發生什麼?
- 23. 如果在SqlDataReader之前關閉SqlConnection,會發生什麼情況?
- 24. 如果消息在MQ中回滾會發生什麼情況?
- 25. 如果CFile :: Write引發異常會發生什麼情況?
- 26. 如果finally塊引發異常,會發生什麼情況?
- 27. 當std :: thread被銷燬時,如果指針指向shared_ptr會發生什麼?
- 28. 未歸檔對象會發生什麼情況?
- 29. 指針和智能指針的區別
- 30. 如果我在Play商店中更改類別,會發生什麼情況?
我實際上遇到了'QSharedPointer'這個問題,它在概念上與boost的'shared_ptr'非常相似。我寫了一篇關於我的發現的博客文章:http://blog.codef00.com/2011/12/15/not-so-much-fun-with-qsharedpointer/ – 2012-03-03 06:13:09