2013-08-27 136 views
5

這是相當不一個問題「如何去做」這是相當「如何做正確的方式」C++ 11非擁有引用/指向unique_ptr的指針?

我開發使用Qt的編輯器,不同的部件顯示兒童和它的(成員)變量。這些小部件中的每一個都應該有一個引用/指向編輯後的孩子的顯示和更改其成員變量的指針。

第一次嘗試是舊的ANSI C方式,我學會了(並且仍然卡在)簡單的原始指針指向使用的對象。它工作正常,但由於C++ 11標準支持智能指針,建議使用它們,我試圖使用它們。

的問題是,我不太清楚什麼是「最好的方法」,在這種情況下使用它們... 閱讀Smart Pointers: Or who owns you baby?Which kind of pointer do I use when?和其他幾個人後,我來到了不同的結論:

的首先是使用*unique_ptr,因爲編輯的對象顯然是創建並刪除其子項的所有者。小部件只是指孩子展示或改變它們。 問題是小部件應該如何參考孩子......

現在我只是仍然使用原始指針我與unique_ptrget()方法得到但這似乎有點缺陷的我。 我仍然可以意外地調用刪除指針並取消智能指針的好處。

第二種方法是使用shared_ptr,因爲許多對象引用了孩子並對其進行編輯。在一個小部件中意外刪除它也不會造成任何傷害,因爲它仍然歸其他對象所有。 問題是他們擁有它。當我想從編輯的對象中刪除它時,我還必須指示所有小部件在它真正離開之前將其刪除。 (這又似乎有瑕疵和容易出錯)

我並不滿足於兩種方式。有沒有一種乾淨的(呃)方式來指向對象的unique_ptr孩子?或者我錯過了一個完全不同的,更好的方法來解決這個問題?

+0

是否需要在引用對象被警告時被引用的對象被銷燬? –

+2

在這種情況下,我們確實需要[愚蠢的智能指針](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3514.pdf)。 –

+0

@BenjaminLindley現在需要提醒他們刪除相應的小部件/控件,並在刪除時不使用它們。例如一個小部件需要獲取一個孩子的座標以將其放置在OpenGL渲染視圖中。但我真的試圖避免這種情況,因爲每個部件都需要對發射的信號做出反應。當所有者能夠確定對象是否存在或不存在時,它會更加理想。 – nils277

回答

2

你想用shared_ptr代替你的unique_ptrweak_ptr來代替你的原始指針。這會給你以後的東西。 weak_ptr不會干擾編輯對象刪除底層對象的能力。

+0

謝謝,這看起來像我正在尋找的確切的東西。 – nils277

1

你的用例並不直接轉化爲需求(如果其他人在你編輯它的時候刪除了這個小部件呢?)但是我假設你不需要超出一個裸指針。

標準庫不提供任何嚴格的指針觀察者類。在觀察者實體:

  • 空,原始類型的可變指針(T *
  • 非空,原始類型的不可變的引用(T &
  • 非空的,可變的引用/類的代理式(std::reference_wrapper<T>
  • 空,自我驗證的,可變的指針如果你想管理對象(std::weak_ptr<T>

一個非空的,可變的指向非管理對象的指針,這是一個相當合理的事情,你可以推出自己的。

但裸指針並沒有那麼糟糕。唯一的區別是它可以是nullptr,並且它在命名空間std內沒有一個很好,很長的顯式名稱。

1

如果您使用的是Qt,您可以考慮使用Qt智能指針來代替std ::智能指針:

或QObject對象:

  • QPointer(或QWeakPointer,特別是在Qt4中)

或實現寫入時複製數據共享,Qt的容器和QString的風格:

還有其他指針類也一樣,但上面的一些最有可能做你想做的事。同樣重要的是,如果你的數據在Qt容器類,QStrings等等,他們用寫時複製語義來處理他們自己的內存,並且通常應該作爲普通的值(有時作爲引用)傳遞而不是指針。

但最重要的,不要使用std::unique_ptrstd::shared_ptr與有父母的QObject,因爲如果家長首先刪除了孩子,那麼的std ::指針將再次刪除它,轟然程序(另一種方式將工作正常,孩子會通知它的父母它已被刪除)。換句話說,如果你將QObject和std :: pointers混合在一起,那麼很可能會出現細微的bug,所以不要這樣做。從你的問題中不清楚你是否在做這件事,以防萬一。

+0

你有一個好點。我沒有想到'QObject'與std ::指針有問題。我認爲'QSharedPointer'和'QWeakPointer'是我的出路,因爲我的對象派生自QObject以利用信號和插槽。 – nils277

+0

@ nill277請注意,'QSharedPointer'存在同樣的問題,它沒有特別支持'父對象'刪除'QObject'。如果沒有父對象,那就沒問題,但否則,同樣的事情也適用。如果你的QObject沒有任何邏輯父/所有者,我想這是一個可行的方法,只是要小心你記得要保持這種方式(比如,沒有允許給父母的構造函數)。如果他們確實有父母,那麼只需使用'QPointer'在其他地方保留弱引用。 – hyde

0

有一個建議爲world's dumbest smart pointer,這是一個非擁有指針。基本上,這是一個T*,它說:「哦,順便說一句,我不要求對這些數據擁有任何所有權」。

在這種情況下,如果unique_ptr消失,您必須管理觀察/被動/啞指針重置 - 半手動生命週期管理。使用原始T*的名稱表明它是非擁有的,就像上面提到的一樣。

這樣做有好處,尤其是當您的對象具有相關的生命週期時。

如果您沒有,那麼shared_ptrweak_ptr的作品。但是請注意,任何擁有weak_ptr的人都可以創建新的shared_ptr,這可以延長共享對象的使用期限,使其超出原始的shared_ptr。這種情況必須發生,否則由於競爭條件,weak_ptr的用戶確保其數據是有效的,然後去使用它,但在這之前shared_ptr的數據被銷燬。

因此,weak_ptr必須能夠防止shared_ptr被破壞(在多線程上下文中阻塞,導致它在單線程上下文中以某種方式「失敗」)。這種情況下的「失敗」由延長壽命組成,它解決了多線程和單線程問題。

(在單線程的問題是,您驗證weak_ptr是好的,做一些事情,導致shared_ptr復位,然後繼續要使用的weak_ptr的數據,而無需重新檢查。天真,它可避免有例外,但仔細檢查後,你會遇到一些問題,在訪問this之前,你必須編寫所有的方法來檢查刪除操作,如果刪除了this,這是一個非常苛刻的要求!)