boostのshared_ptr(shared_ptr< Y> const& r、T * p)は何に使用されますか?

StackOverflow https://stackoverflow.com/questions/1403465

質問

boost :: shared_ptr には珍しいコンストラクターがあります

template<class Y> shared_ptr(shared_ptr<Y> const & r, T * p);

そして、これが何に役立つのか少し戸惑っています。基本的には r と所有権を共有しますが、 .get() p を返します。 ない r.get()

これは、次のようなことができることを意味します。

int main() {
    boost::shared_ptr<int> x(new int);
    boost::shared_ptr<int> y(x, new int);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

そして、あなたはこれを取得します:

0x8c66008
0x8c66030
2
2

ポインターは別々ですが、両方とも use_count が2であると主張していることに注意してください(同じオブジェクトの所有権を共有しているため)。

したがって、 x が所有する int は、 x または y はその前後です。ドキュメントが正しいことを理解していれば、2番目の int は決して破壊されません。次のテストプログラムでこれを確認しました。

struct T {
    T() { std::cout << "T()" << std::endl; }
    ~T() { std::cout << "~T()" << std::endl; }
};

int main() {
    boost::shared_ptr<T> x(new T);
    boost::shared_ptr<T> y(x, new T);

    std::cout << x.get() << std::endl;
    std::cout << y.get() << std::endl;

    std::cout << x.use_count() << std::endl;
    std::cout << y.use_count() << std::endl;
}

この出力(予想どおり):

T()
T()
0x96c2008
0x96c2030
2
2
~T()

だから... 1つのポインタの所有権を共有するが、使用されると別のポインタ(所有していない)のように動作するこの異常な構造の有用性は何ですか

役に立ちましたか?

解決

次のように、クラスメンバーを共有し、クラスのインスタンスが既にshared_ptrである場合に便利です。

struct A
{
  int *B; // managed inside A
};

shared_ptr<A>   a( new A );
shared_ptr<int> b( a, a->B );

使用回数と内容を共有します。メモリ使用量の最適化です。

他のヒント

leiz's を展開するには piotrのの回答、 shared_ptr&lt;&gt; 「エイリアス」はWG21論文&quot; C ++ 0x、リビジョン2の shared_ptr の改善&quot;

  

III。エイリアスのサポート

     

上級ユーザーには、多くの場合、    shared_ptr を作成する機能   所有権を共有するインスタンス p   別の(マスター) shared_ptr q が   ベースではないオブジェクトを指します    * q の。 * p は、メンバーまたは   たとえば、 * q の要素。この   セクションは追加を提案します   これに使用できるコンストラクタ   目的。

     

これの興味深い副作用   表現力の向上は    * _ pointer_cast 関数は   ユーザーコードで実装する。の    make_shared ファクトリ関数の提示   このドキュメントの後半でも   パブリックのみを使用して実装    shared_ptr のインターフェース   エイリアスコンストラクタ。

     

影響:

     

この機能は、   下位互換性のある shared_ptr   その表現力を高める方法   力としたがって強く   C ++ 0xに追加することを推奨   標準。ソースを紹介しません-   バイナリ互換性の問題。

     

提案テキスト:

     

shared_ptr に追加   [util.smartptr.shared]以下   コンストラクター:

     
template<class Y> shared_ptr( shared_ptr<Y> const & r, T * p );
  
     

次を追加します   [util.smartptr.shared.const]:

     
<*>          

効果: p を保存し、 r と所有権を共有する shared_ptr インスタンスを構築しますcode>。

         

後条件: get()== p&amp;&amp; use_count()== r.use_count()

         

スロー:なし。

         

[注:ぶら下がりポインターの可能性を避けるために、ユーザーは     このコンストラクタの p が少なくとも有効であることを保証する必要があります      r の所有権グループが破棄されるまで。 -メモを終了します。]

         

[注:このコンストラクターは、 empty shared_ptr の作成を許可します     NULL以外の格納されたポインタを持つインスタンス。 -メモを終了します。]

  

これを使用して、動的なキャストポインタを保持することもできます。例:

class A {};
class B: public A {};

shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));

一部のドライバーまたは下位レベルのAPIのデータ構造へのポインターがあり、下位レベルのAPIまたはその他の手段で追加データを割り当てる場合があります。この場合、use_countを増やすことは興味深いかもしれませんが、最初のポインターが他のデータポインターを所有している場合は追加のデータを返します。

shared_ptrのエイリアスコンストラクタを小さなライブラリで使用しています:

http://code.google.com/p/infectorpp/ (ちょうど私のシンプルなIoCコンテナー)

要点は、既知のタイプのshared_ptrがポリモーフィッククラス(タイプを知らない)から返される必要があるためです。 shared_ptrを必要な型に暗黙的に変換できませんでした。

ファイル内&quot; InfectorHelpers.hpp &quot; (72-99行目)IAnySharedタイプの動作を確認できます。

エイリアスコンストラクターは、実際に指し示しているポインターを削除しないshared_ptrを作成しますが、元のオブジェクトへの参照カウンターを引き続き増加し、非常に便利です。

基本的に、エイリアスコンストラクターを使用して任意のものへのポインターを作成し、それを参照カウンターとして脅かすことができます。

//my class
std::shared_ptr<T> ist;
int a; //dummy variable. I need its adress

virtual std::shared_ptr<int> getReferenceCounter(){
    return std::shared_ptr<int>(ist,&a); //not intended for dereferencing
}

virtual void* getPtr(); //return raw pointer to T

現在、「参照カウンタ」の両方があります。 Tのインスタンスへのポインター、エイリアスコンストラクターで何かを作成するのに十分なデータ

std::shared_ptr<T> aPtr( any->getReferenceCounter(), //share same ref counter 
               static_cast<T*>(any->getPtr()) ); //potentially unsafe cast!

エイリアシングコンストラクターのこの使用法を発明したふりはしませんが、他の誰かが同じことをしているのを見たことはありません。その汚いコードが機能するかどうかを推測している場合、答えはイエスです。

&quot; shared_ptr&lt; B&gt;の場合b(a、dynamic_cast&lt; B *&gt;(a.get())); &quot;

スマートポインターを使用することはお勧めの方法ではないと思います。

この型変換の推奨される方法は次のとおりです。

shared_ptr<B> b(a);

Boostドキュメントでは、次のように言及されています。

  

shared_ptr&lt; T&gt; は暗黙的に指定できます   T *のたびに shared_ptr&lt; U&gt; に変換されます   暗黙的にU *に変換できます。に   特に、 shared_ptr&lt; T&gt; は   暗黙的に shared_ptr&lt; T&gt;に変換可能const 、    shared_ptr&lt; U&gt; へ。ここでUは   Tのアクセス可能なベース、および    shared_ptr&lt; void&gt;

それに加えて、 dynamic_pointer_cast もあります スマートポインターオブジェクトで直接変換を行うことができ、これらの2つの方法はどちらも、手動で生のポインターをキャストする方法よりもはるかに安全です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top