boostのshared_ptr(shared_ptr< Y> const& r、T * p)は何に使用されますか?
-
05-07-2019 - |
質問
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つの方法はどちらも、手動で生のポインターをキャストする方法よりもはるかに安全です。