web-dev-qa-db-ja.com

弱い参照を持つunique_ptrのような別のタイプのスマートptr?

最近、_unique_ptr_も_shared_ptr_も適切な解決策ではないように見えるという問題が発生しました。したがって、別の種類のスマートptr(以下で説明)を発明することを検討していますが、「確かに私はこれを最初に望んでいるのではありません」と考えました。

だから私のハイレベルな質問は:

  • 以下のデザインは意味がありますか?
  • 既存のスマートptr(または他の_std::_機能)でこれを実現する方法はありますか?おそらく何か不足していますか?

要件:

  • _unique_ptr_ のように単一の所有権が欲しい
    • つまり、(_shared_ptr_の動作とは異なり)単一の所有ポインタが停止した場合にのみ、基になるオブジェクトを解放する必要があります。
  • オブジェクトが削除されたときに「認識」されているオブジェクトを参照するための追加の方法が必要です。つまり、_weak_ptr_のようなものですが、単一の所有権モデルで使用されます。
  • スレッドセーフは必要ありません

動機付けの例:

インターフェイスポインターのリストを反復処理し、それらのメソッドを呼び出しているとします。これらのメソッドの一部は、リストの後半の項目が削除される原因となる場合があります。

単純なポインタを使用すると、削除されたアイテムの参照がぶら下がっています。

提案された設計:

所有ポインタ_my_ptr_および非所有参照_my_weak_ptr_を呼び出します。

特定のオブジェクトについて、次のような図が表示される場合があります。

_                             _______
my_ptr<Obj> owner ---------> |Obj* | -------> [Obj data ... ]
                      +----> |count|
                      | +--> |_____|
my_weak_ptr<Obj> A ---+ |
                        |
my_weak_ptr<Obj> B -----+
_

_my_ptr_には、_unique_ptr_とほぼ同じインターフェースがあります。内部的には、実際には単なる「実際の」ポインタである「制御ブロック」へのポインタと、制御ブロック自体の参照カウントを格納します。破棄時に、_my_ptr_は制御ブロックポインタをNULLに設定し、refcountをデクリメントします(必要に応じて制御ブロックを削除します)。

_my_weak_ptr_はコピー可能であり、実際の_Obj*_を返すget()メソッドがいくつかあります。ユーザーはこれを使用する前にNULLをチェックする必要があります。破棄時には、_my_weak_ptr_はカウントを減らします(必要に応じて、制御ブロックを削除します)。

欠点は、アクセスごとにメモリを2回ホップすることです。 _my_ptr_の場合、これは真の_Obj*_を内部に格納することでも軽減できますが、_my_weak_ptr_参照は常にそのダブルホップコストを支払う必要があります。


編集:リンクからのいくつかの関連質問:

したがって、このようなものに対する需要があるようですが、スラムダンクソリューションはありません。スレッドセーフが必要な場合は、_shared_ptr_および_weak_ptr_が適切な選択ですが、そうでない場合は、不要なオーバーヘッドが追加されます。

_boost::local_scoped_ptr_ もありますが、それでも共有所有権モデルです。 _unique_ptr_のように、所有するポインタのコピーを防止したい。

6
jwd

余分なブロックを割り当てないデザインがありますが、代わりに3つのポインターのサイズのポインターオブジェクトを作成します。ポインターは二重リンクリストのノードであり、各弱参照は同じリストのノードです。

欠点は、直線的な削除の複雑さ(各参照を無効にする必要がある)であり、これを効率的にスレッドセーフにすることは不可能です。

利点は、共有ポインターと弱いポインターの両方の高速逆参照です。

どこでこのアイデアを見たり聞いたりしたのか正確には覚えていません...

1
Alex Guteniev