5

最近、このデータ構造に似たものが必要な状況に頻繁に遭遇しています。

制限:C++03標準。


 +-----+--------------+               +----+
 |node0| NodeDataRef ->-------------->|data|
 +-----+--------------+               +----+
 +-----+--------------+                ^^ ^
 |node1| NodeDataRef ->----------------+| |
 +-----+--------------+                 | |
 +-----+--------------+                 | |
 |node2| NodeDataRef ->-----------------+ |
 +-----+--------------+                   |
                                          |
 +-----+--------------+                   |
 |root | RootDataRef ->-------------------+
 +-----+--------------+              
  1. いくつかのNodeクラスがあり、それぞれが「」の同じインスタンスへの「参照」(think )をNode保持します(クラス、構造、何でも-動的に割り当てられます)。 NodeDataRefshared_ptrData
  2. 同じ""への参照(今回はthink )を保持する" Root"または"master"ノード/クラスもあります。RootDataRefweak_ptrData
  3. すべてNodeのsが破棄されると、dataも破棄され、 /RootDataRefに設定されます。つまり、のように振る舞い、0NULLNodeDataRefshared_ptr<Data>RootDataRefweak_ptr<Data>
  4. ただし、ルートノードは、アクティブながまだ存在する場合でも、データを強制的に破棄する可能性がありますNodeDataRef。この状況NodeDataRefでは、データを指していたすべてのsが/に設定され、NULLまた/0に設定RootDataRefされます。0NULL

つまりweak_ptr<Data>、リンクされているすべてのを強制的に破壊することができますshared_ptr<Data>

  1. このパターン/スマートポインタタイプには名前がありますか?
  2. BoostまたはQt4を使用してこれをすばやく実装するにはどうすればよいですか?(「迅速に」とは、参照のリストを維持するためのクラスを作成しないことを意味します)
4

5 に答える 5

4

このパターン/スマートポインタタイプには名前がありますか?

私の知る限り、いいえ、これは一般的に使用される名前の典型的な所有パターンではありません。

BoostまたはQt4を使用してこれをすばやく実装するにはどうすればよいですか?(「迅速に」とは、参照のリストを維持するためのクラスを作成しないことを意味します)

このユースケースには、共有所有権のポイントが無効になるため、事前にパッケージ化された所有権ポリシーはありません。特定のオブジェクトへの共有ポインターが複数存在する場合、定義上、それらの共有ポインターはそのオブジェクトを存続させる必要があります。共有ポインタが与えられた場合、それは私がそれを解放するまでオブジェクトが存在することを保証します。

1つのマスターオブジェクトが、他のオブジェクトがそのオブジェクトへの共有ポインターを保持しているかどうかに関係なく、ポイントされたオブジェクトの破棄をコマンドできるようにする場合は、共有ポインターのすべてのホルダーにコマンドを送信させるための別のメカニズムを理解する必要があります。それを解放するためのそのオブジェクト。

アップデート:

これを「迅速に」機能させるための「ハッキー」なソリューションが存在しますが、それらのいずれかを使用することはお勧めしません。このパターンは、誰かがあなたのコードを読んだときにそれが明らかになるようにするのに十分なほど非定型です(今から数か月後のあなたを含む)。

ラッパーやカスタムデリッターなどのどこかに隠されるのではなく、マスターオブジェクトと他の所有者の間の明示的な通信パターンを通じて意図を明確にする必要があります。

于 2013-03-24T12:44:38.937 に答える
0

どこでshared_ptr<T>使用できますか。演算子newを使用してインスタンスを作成することに問題がないと仮定します)。weak_ptr<T>T = scoped_ptr<Data>Data

を使用shared_ptrして割り当てる必要がありますmake_shared<unique_ptr<Data>>(new Data(...));

ルートweak_ptrは、を呼び出すことによって強制的に削除できます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;
    }   
};

新しいNormalHandlesの初期化は次のようになります。

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

于 2013-03-24T13:02:54.307 に答える
0

なぜこれを実行したいかはわかりませんが、これは(非常に)ハック的なソリューションであり、NodeDataRef(理想的にはそのクラスのメソッドとして実行される)へのアクセスごとに追加のコードを実行する必要があります。

オブジェクトと一緒にセンチネルオブジェクトを作成しますDataRootDataRefそれへの所有参照とすべてのノードに弱参照を与えます。次に、にアクセスする前NodeDataRefに、番兵への弱参照がまだ有効であることを確認します。からの削除を強制するrootには、番兵への所有参照を削除して、NodeDataRefs内のすべての弱参照を無効にします。

于 2013-03-24T13:09:28.647 に答える
0

実装が簡単な(ただし最も効率的ではない)方法の1つは、2つのshared_ptrレイヤーを使用することです
。shared_ptr<shared_ptr <data >>
ルートにはそれへの弱いポインターがあり、強制的に破棄する場合は、内部のshared_ptrデータをリセットします。 (ロックの下で実行してください!)
他のすべてのノードは通常どおりに使用しますが、使用する前に内部shared_ptrの有効性を確認する必要があります。

于 2013-03-24T13:13:52.823 に答える
0

Qt固有の答えは誰にも与えられていないので(奇妙ですか?)、共有ポインタークラスについては少し荒いですが、それを試してみます。

QSharedPointerRootDataRefとしてを生成し、そこからノードを生成できるようです。最初のを作成したら、 QSharedPointer::toWeakRefを使用してを弱いポインタに降格します。そうすれば、すべてのsを削除すると、元のポインターが削除され、ゼロに設定する必要があります(おそらくそうではありませんか?)。NodeDataRefRootDataRefNodeDataRefRootDataRef

ルートを使用して元のオブジェクトを削除する必要がある場合は、QWeakPointer :: toStrongRefを使用してオブジェクトを強力な参照に再プロモートし、削除すると、すべてのノードが自動的にゼロに割り当てられます。


編集:あるいは、本当にポインタが必要ですか?これが実際の共有オブジェクトではなく共有データの場合である場合は、QSharedDataPointer、特にQExplicitlySharedDataPointerでのQtの暗黙的な共有スキームを検討してください。

于 2013-03-25T18:46:48.390 に答える