次の方法で共有


方法: shared_ptr インスタンスを作成して使用する

shared_ptr の型にいくつかの所有者がメモリ オブジェクトの有効期間を管理する必要があるシナリオ用にデザインされた C++ の標準ライブラリのスマート ポインターです。、それがコピーできる shared_ptr を初期化後に関数の引数の値を渡し、shared_ptr の他のインスタンスに再配置。同じへのすべてのインスタンスのポイントが新しい shared_ptr が追加されるたびにオブジェクト、その 1 文字の "コントロール ブロック" へのアクセスに参照カウントがスコープの外に出るインクリメント、デクリメント、および共有、またはリセットされます。参照カウントがゼロに達すると、コントロール ブロックは、メモリ リソースおよび自体を削除します。

次の図は、1 種類のメモリ位置を示す shared_ptr の複数のインスタンスを示します。

共有ポインター

使用例

メモリ リソースが初めて作成されたときには、可能な限り、shared_ptr の作成に make_shared (<memory>) 関数を使用します。make_shared は例外セーフです。これは、コントロール ブロックとリソースのメモリを割り当てるには、同じ呼び出しを使用することで、構造のオーバーヘッドが減少します。make_sharedを使用しない場合は、shared_ptr のコンストラクターに渡す前にオブジェクトを作成するには、明示的に新しい式を使用する必要があります。次の例では、新しいオブジェクトとともに shared_ptr の宣言と初期化のさまざまな方法を示します。


// Use make_shared function when possible.
auto sp1 = make_shared<Song>(L"The Beatles", L"Im Happy Just to Dance With You");

// Ok, but slightly less efficient. 
// Note: Using new expression as constructor argument
// creates no named variable for other code to access.
shared_ptr<Song> sp2(new Song(L"Lady Gaga", L"Just Dance"));

// When initialization must be separate from declaration, e.g. class members, 
// initialize with nullptr to make your programming intent explicit.
shared_ptr<Song> sp5(nullptr);
//Equivalent to: shared_ptr<Song> sp5;
//...
sp5 = make_shared<Song>(L"Elton John", L"I'm Still Standing");

次の例は、別の shared_ptrによって既に割り当てられているオブジェクトの共有所有権で実行する shared_ptr のインスタンスを宣言して初期化する方法を示しています。sp2 が初期化 shared_ptrであると仮定します。

//Initialize with copy constructor. Increments ref count.
auto sp3(sp2);

//Initialize via assignment. Increments ref count.
auto sp4 = sp2;

//Initialize with nullptr. sp7 is empty.
shared_ptr<Song> sp7(nullptr);

// Initialize with another shared_ptr. sp1 and sp2
// swap pointers as well as ref counts.
sp1.swap(sp2);

shared_ptr は、要素をコピーするアルゴリズムを使用しているときにテンプレート ライブラリの (STL) の標準的なコンテナーでも役立ちます。認証を必要とすると、がではない限り shared_ptrの要素をラップし、基になるメモリが有効である理解の他のコンテナーにコピーします。次の例では、ベクターに shared_ptr のインスタンスの replace_copy_if のアルゴリズムを使用する方法を示します。

vector<shared_ptr<Song>> v;

v.push_back(make_shared<Song>(L"Bob Dylan", L"The Times They Are A Changing"));
v.push_back(make_shared<Song>(L"Aretha Franklin", L"Bridge Over Troubled Water"));
v.push_back(make_shared<Song>(L"Thal�a", L"Entre El Mar y Una Estrella"));

vector<shared_ptr<Song>> v2;
remove_copy_if(v.begin(), v.end(), back_inserter(v2), [] (shared_ptr<Song> s) 
{
    return s->artist.compare(L"Bob Dylan") == 0;     
});


for_each(v2.begin(), v2.end(), [] (shared_ptr<Song> s)
{
    wcout << s->artist << L":" << s->title << endl;
});

dynamic_pointer_cast、shared_ptrをキャストに static_pointer_castと const_pointer_cast を使用できます。これらの関数は dynamic_cast、static_castと const_cast の演算子に似ています。次の例では、基本クラスの shared_ptr のベクターの各要素の派生型をテストする方法を示します。それらに関する要素と表示の情報をコピーします。

    vector<shared_ptr<MediaAsset>> assets;

    assets.push_back(shared_ptr<Song>(new Song(L"Himesh Reshammiya", L"Tera Surroor")));
    assets.push_back(shared_ptr<Song>(new Song(L"Penaz Masani", L"Tu Dil De De")));
    assets.push_back(shared_ptr<Photo>(new Photo(L"2011-04-06", L"Redmond, WA", L"Soccer field at Microsoft.")));

    vector<shared_ptr<MediaAsset>> photos;

    copy_if(assets.begin(), assets.end(), back_inserter(photos), [] (shared_ptr<MediaAsset> p) -> bool
    {
        // Use dynamic_pointer_cast to test whether
        // element is a shared_ptr<Photo>.
        shared_ptr<Photo> temp = dynamic_pointer_cast<Photo>(p);        
        return temp.get() != nullptr;
    });

    for_each(photos.begin(), photos.end(), [] (shared_ptr<MediaAsset> p)
    {
        // We know that the photos vector contains only 
        // shared_ptr<Photo> objects, so use static_cast.
        wcout << "Photo location: " << (static_pointer_cast<Photo>(p))->location_ << endl;
    });

別の関数に shared_ptr を次のように渡すことができます:

  • 値を shared_ptr を渡します。これは、コピー コンストラクターを呼び出し、参照カウントをインクリメントし、呼び出し先に所有者を説明します。shared_ptr のオブジェクトの数を渡しているかによって重要可能性がある操作が、このオーバーヘッドがあります。呼び出し先は所有者であるように、呼び出し元と呼び出し先の間にコード コントラクト (暗黙的に指定されるか、明示的な要求するときはこのオプションを使用します。

  • 参照または const 参照を shared_ptr を渡します。この場合、参照カウントがインクリメントせず、呼び出し元がスコープの出かけない限り、呼び出し先はポインターにアクセスできます。または、呼び出し先はそれにより参照に基づいて shared_ptr を作成し、共有所有者になるようにできます。呼び出し元と呼び出し先がわからない場合、または shared_ptr を渡し、コピー操作をパフォーマンス上の理由で回避したくない場合がある場合に、このオプションを使用します。

  • 基になるオブジェクトに基になるポインターまたは参照を渡します。これは、オブジェクトを使用することを、呼び出し先ができますが所有権を共有するか、有効期間を延長することはできません。呼び出し先は、ポインターから shared_ptr を作成する場合は、新しい shared_ptr は元に依存しない、基になるリソースを制御することはできません。呼び出し元は shared_ptr の有効期間の所有権を保持することを呼び出し元と呼び出し先の間で決められたを明確に指定した場合に、このオプションを使用します。

  • 呼び出し先は基になるリソースの所有権を共有する必要があるかどうかを判断 shared_ptrを渡す方法を決定するとき。 "所有者" が要求を必要とする限り、基になるリソースを維持できるオブジェクトでまたは関数です。呼び出し先は (関数) の有効期間を超えるポインターの有効期間を拡張する呼び出し元が保証は前者を使用します。呼び出し先は有効期間を延長するかどうかを気に、参照渡しには、呼び出し先では、コピーようにします。

  • 前に、呼び出し元関数がを返すヘルパー関数は、ポインターを使用して返すことが基になるヘルパー関数ポインターへのアクセスを付ける必要がある場合、わかっている場合は、関数が基のポインターの所有権を共有する必要がありません。この場合は、呼び出し元の shared_ptrの有効期間内のポインターにアクセスする必要があります。この場合、参照を shared_ptr を渡す方が安全です、基になるオブジェクトへのポインター、または参照を渡します。この方法を渡すことは、パフォーマンスが向上し、または、プログラミングの意図を表現するのに役立つ場合があります。

  • しかし、たとえば **std:vector<shared_ptr<T>>**では、ラムダ式の本体または名前付き関数オブジェクトに各 shared_ptr を渡す必要があることができます。ラムダのまたは関数ポインターを貯えなかったら、各要素のコピー コンストラクターを起動しないように参照を shared_ptr を渡します。

shared_ptr のインスタンスが所有しているメモリのポインターを比較を有効にするには shared_ptr がさまざまな比較演算子をオーバーロードする方法を次の例に示します。


// Initialize two separate raw pointers.
// Note that they contain the same values.
auto song1 = new Song(L"Village People", L"YMCA");
auto song2 = new Song(L"Village People", L"YMCA");

// Create two unrelated shared_ptrs.
shared_ptr<Song> p1(song1);    
shared_ptr<Song> p2(song2);

// Unrelated shared_ptrs are never equal.
wcout << "p1 < p2 = " << std::boolalpha << (p1 < p2) << endl;
wcout << "p1 == p2 = " << std::boolalpha <<(p1 == p2) << endl;

// Related shared_ptr instances are always equal.
shared_ptr<Song> p3(p2);
wcout << "p3 == p2 = " << std::boolalpha << (p3 == p2) << endl; 

参照

概念

スマート ポインター (Modern C++)