26

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

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

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

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()

では、あるポインターの所有権を共有するが、使用すると別のポインター (所有していない) のように機能する、この異常な構造の有用性は何ですか。

4

6 に答える 6

29

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

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

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

それらは使用回数などを共有します。これは、メモリ使用量の最適化です。

于 2009-09-10T05:29:33.120 に答える
8

leizpiotrの回答を拡張するために、このshared_ptr<>「エイリアシング」の説明は、WG21の論文「Improvingfor shared_ptrC ++ 0x、Revision2」からのものです。

III。エイリアシングのサポート

上級ユーザーは、所有権を別の(マスター)と共有するが、のベースではないオブジェクトを指すshared_ptr インスタンスを作成する機能を必要とすることがよくあります。たとえば、のメンバーまたは要素である可能性があります。このセクションでは、この目的に使用できる追加のコンストラクターを提案します。pshared_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]に以下を追加します。

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

効果:shared_ptr所有権を保存pおよび共有 するインスタンスを構築しますr

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

スロー:何も。

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

[注:このコンストラクターを使用する と、NULL以外の格納ポインターを使用して空の インスタンスを作成できます。-注を終了します。]shared_ptr

于 2009-09-10T05:39:23.947 に答える
4

これを使用して、動的にキャストされたポインターを保持することもできます。つまり、次のようになります。

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

shared_ptr<A> a(new B);
shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));
于 2010-08-11T11:00:10.860 に答える
2

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

于 2009-09-10T05:32:29.540 に答える
0

shared_ptr<B> b(a, dynamic_cast<B*>(a.get()));」の場合

スマートポインタの使用はお勧めできません。

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

shared_ptr<B> b(a);

Boostドキュメントでは、次のように述べられています。

shared_ptr<T>shared_ptr<U>T*を暗黙的にU*に変換できる場合はいつでも、暗黙的にに変換できます。特に、shared_ptr<T>は暗黙的にに変換可能です。ここで、UはTのアクセス可能なベースであり shared_ptr<T> const、に変換できます。shared_ptr<U>shared_ptr<void>

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

于 2011-01-14T11:25:38.357 に答える
0

私の小さなライブラリでは、shared_ptr のエイリアシング コンストラクタを使用しています。

http://code.google.com/p/infectorpp/ (単純な IoC コンテナー)

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

ファイル " InfectorHelpers.hpp " (行 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!

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

于 2013-07-13T16:11:28.533 に答える