2013-03-24 20 views
5

最近,我經常遇到需要與此數據結構類似的情況。智能指針/編碼模式的名稱

限制:C++ 03標準。


+-----+--------------+    +----+ 
|node0| NodeDataRef ->-------------->|data| 
+-----+--------------+    +----+ 
+-----+--------------+    ^^^
|node1| NodeDataRef ->----------------+| | 
+-----+--------------+     | | 
+-----+--------------+     | | 
|node2| NodeDataRef ->-----------------+ | 
+-----+--------------+     | 
              | 
+-----+--------------+     | 
|root | RootDataRef ->-------------------+ 
+-----+--------------+    
  1. 有幾個Node類,其中每個Node持有NodeDataRef 「參考」(認爲shared_ptr)爲 「Data」(類,結構,不管是誰 - 動態分配)的同一個實例。
  2. 還有一個「Root」或「主」節點/類,它將RootDataRef引用(此時,認爲是weak_ptr)保存爲相同的「Data」。
  3. 當全部Node被銷燬時,data也被銷燬,並且RootDataRef被設置爲0/NULL。即NodeDataRef行爲像shared_ptr<Data>RootDataRef行爲像weak_ptr<Data>
  4. 然而根節點可以強制的數據的毀壞,即使仍有活性NodeDataRef秒。在這種情況下,所有指向數據的NodeDataRef都設置爲NULL/0,而RootDataRef也設置爲0/NULL

即, weak_ptr<Data>可以強制銷燬所有鏈接的shared_ptr<Data>

  1. 此模式/智能指針類型是否有名稱?
  2. 我該如何快速使用Boost或Qt 4來實現? (「快」是指未經寫一個類來維持引用列表)

回答

4

請問這種模式/智能指針類型都有一個名字?

據我所知,不,這不是一個典型的擁有常用名稱的所有權模式。

如何使用Boost或Qt 4快速實現? (「快速」意味着無需編寫一個類來維護引用列表)

對於此用例,沒有預包裝的所有權策略,因爲這會打破共享所有權點。如果存在多個指向給定對象的共享指針,那麼根據定義,這些共享指針必須保持該對象存活。如果我得到一個共享指針,這是一個保證該對象將存在,直到我釋放它。

如果你想要一個主對象能夠命令銷燬指向對象,無論其他對象是否持有指向它的共享指針,那麼你將不得不想出一些單獨的機制讓它命令所有持有者一個指向該對象的共享指針來釋放它。

UPDATE:

雖然「哈克」的解決方案存在,使這項工作「快」,我也不會你使用其中的任何建議。當有人讀取你的代碼(包括你在幾個月後)時,這種模式對於你想要它是明顯的是非典型的。

您的意圖應該通過主對象和其他所有者之間的顯式通信模式來明確,而不是隱藏在包裝器,定製刪除器或其他任何地方。

+0

我問了一個「快速」解決方案,因爲我知道如何自己編寫這個文件,但是認爲可能有某種類型的文件(我已經可以使用的available_class) – SigTerm 2013-03-24 16:55:29

+0

@SigTerm:好的,我不知道的任何「最佳實踐」來實現這種設計模式,我只想指出,無論選擇哪種解決方案,我都希望在代碼中清晰可見,而不是將其包裝在一些定製所有權策略中。 – 2013-03-24 16:58:51

0

您可以使用shared_ptr<T>weak_ptr<T>其中T = scoped_ptr<Data>。假設你在運營商新建Data實例方面沒問題)。

shared_ptr應使用make_shared<unique_ptr<Data>>(new Data(...));

根的weak_ptr可能迫使刪除通過調用新NormalHandles root.lock().reset()

template <typename T> 
struct RootHandle : public boost::weak_ptr< boost::scoped_ptr<T> > 
{ 
    typedef boost::weak_ptr< boost::scoped_ptr<T> > weak_type; 
    typedef boost::shared_ptr< boost::scoped_ptr<T> > strong_type; 

    RootHandle() {} 
    RootHandle(const weak_type& impl) 
     :weak_type(impl) {} 


    T* get() const 
    { 
     strong_type x = lock(); 
     return (x) ? x->get() : 0; 
    } 

    void reset() 
    { 
     strong_type x = lock(); 
     if (x) 
      x->reset(); 
    } 
}; 

template <typename T> 
struct NormalHandle : public boost::shared_ptr< boost::scoped_ptr<T> > 
{ 
public: 
    typedef boost::shared_ptr< boost::scoped_ptr<T> > strong_type; 

    NormalHandle() {} 
    NormalHandle(const strong_type& impl) 
     :strong_type(impl) {} 

    T* get() const 
    { 
     boost::scoped_ptr<T>* ppx = strong_type::get(); 
     return (0 != ppx) ? ppx->get() : 0; 
    } 
}; 

初始化分配是這樣的:

NormalHandle<Data> handle1(boost::make_shared< boost::scoped_ptr<Data> >(new Data(4, 3, "abc")));

+0

是不是'unique_ptr '只是C++ 11的一部分? OP僅指定C++ 03。 – jerry 2013-03-24 13:12:34

+0

好的,你必須使用'boost :: scoped_ptr'來代替。幾乎任何可以儘早解僱的「範圍守衛」型機制都可以在這裏發揮作用。 – yonil 2013-03-24 13:18:14

0

我米不知道你爲什麼想這樣做,但這是一個(非常)hacki sh解決方案,這些解決方案在每次訪問NodeDataRef時都需要額外的代碼(作爲該類的一種方法來完成)。

創建一個哨兵對象以及您的Data對象。給予RootDataRef擁有一個參考,並且所有節點都是一個弱引用。然後,在每次訪問NodeDataRef之前,檢查對哨兵的弱引用是否仍然有效。要強制從root刪除,請刪除擁有對該標記的引用,導致NodeDataRef中的所有弱引用無效。

0

一個容易實現的(但不是最有效的)方法是有雙重的shared_ptr層:
shared_ptr的< shared_ptr的<數據>>
根將有一個微弱的指針指向,當你想強制破壞你將重置內部shared_ptr數據(在鎖定下執行)
所有其他節點將正常使用它,但必須在使用它之前檢查內部shared_ptr的有效性。

0

沒有人給出Qt特定的答案(奇怪?),所以我會給它一個破解,儘管我對共享指針類有點粗糙。

看起來,您可以生成RootDataRef作爲QSharedPointer,並從中產生節點。在創建第一個NodeDataRef後,使用QSharedPointer::toWeakRefRootDataRef降級爲a weak pointer。這樣,當您刪除所有NodeDataRef時,原始指針將被刪除,並且RootDataRef應該(可能不是?)被設置爲零。

如果您需要使用根目錄刪除原始對象,只需使用QWeakPointer::toStrongRef將其重新提升爲強參考,然後將其刪除,並且應將所有節點自動分配爲零。


編輯:另外,你是否真的需要一個指針?如果這是共享數據而不是實際共享對象的情況,那麼您可以考慮QSharedDataPointer中的Qt隱式共享方案,尤其是QExplicitlySharedDataPointer