Sdílet prostřednictvím


Postupy: Vytváření a používání instancí ukazatelů shared_ptr

Typ shared_ptr je inteligentní ukazatel ve standardní knihovně jazyka C++ určený pro scénáře, ve kterých musí více než jeden vlastník spravovat dobu života objektu v paměti.Po inicializaci typu shared_ptr jej lze zkopírovat, předat hodnotou argumentům funkce nebo přiřadit dalším instancím typu shared_ptr.Všechny tyto instance ukazují na stejný objekt a sdílejí přístup k jednomu „řídícímu bloku“, který zvyšuje a snižuje počet odkazů, kdykoli je nová instance typu shared_ptr přidána, dostane se mimo rozsah nebo je obnovena.Když počet odkazů dosáhne nuly, řídicí blok odstraní prostředky paměti a sám sebe.

Následující obrázek znázorňuje několik instancí typu shared_ptr, které odkazují na jedno umístění v paměti.

Sdílený ukazatel

Příklad

Kdykoli je to možné, použijte funkci make_shared (<memory>) pro vytvoření instance typu shared_ptr, když je prostředek paměti vytvořen poprvé.Funkce make_shared zaručuje bezpečnost výjimek.Používá stejné volání pro přidělení paměti řídícímu bloku a prostředku a tím snižuje zatížení při jejich konstrukci.Pokud funkci make_shared nepoužijete, je pro vytvoření objektu před jeho předání konstruktoru typu shared_ptr nutné explicitně použít nový výraz.Následující příklad ukazuje různé způsoby deklarace a inicializace instancí typu shared_ptr společně s novým objektem.

// 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");

Následující příklad ukazuje deklaraci a inicializaci instancí typu shared_ptr, které převezmou sdílené vlastnictví objektu, který již byl vytvořen jinou instancí typu shared_ptr.Předpokládejme, že proměnná sp2 je inicializována instancí typu 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);

Typ shared_ptr je také užitečný v kontejnerech knihovny STL při použití algoritmů, které kopírují prvky.Prvky lze zabalit do instance typu shared_ptr a poté je zkopírovat do jiných kontejnerů s vědomím, že základní paměť je platná tak dlouho, dokud ji potřebujete a ne déle.Následující příklad ukazuje, jak použít algoritmus replace_copy_if s instancemi typu shared_ptr v instanci typu vector.

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 (const auto& s : v2)
{
    wcout << s->artist << L":" << s->title << endl;
}

K přetypování instance typu shared_ptr lze použít funkce dynamic_pointer_cast, static_pointer_cast a const_pointer_cast.Tyto funkce se podobají operátorům dynamic_cast, static_cast a const_cast.Následující příklad ukazuje, jak otestovat odvozený typ základních tříd každého prvku vektoru instancí typu shared_ptr a poté tyto prvky zkopírovat a zobrazit o nich informace.

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 (const auto&  p : photos)
{
    // 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;
}

Instanci typu shared_ptr lze jiné funkci předat následujícími způsoby:

  • Předání instance typu shared_ptr hodnotou.To zavolá kopii konstruktoru, zvýší počet odkazů a volaného učiní vlastníkem.Tato operace představuje malé množství režie, což může být významné v závislosti na tom, kolik objektů shared_ptr předáváte.Tuto možnost použijte, pokud kontrakt (implicitní nebo explicitní) mezi volajícím a volaným vyžaduje, aby volaný byl vlastníkem.

  • Předání instance typu shared_ptr odkazem nebo odkazem const.V tomto případě počet odkazů není zvýšen a volaný má k ukazateli přístup, dokud se volající nedostane mimo rozsah platnosti.Nebo volaný může rozhodnout o vytvoření objektu shared_ptr založeném na tomto odkazu a tím se stát sdíleným vlastníkem.Tuto možnost použijte, když volající nezná volaného nebo když je nutné předat instanci typu shared_ptr a chcete se vyhnout operaci kopírování z důvodů výkonu.

  • Předání základního ukazatele nebo odkazu na základní objekt.Umožňuje volanému tento objekt použít, ale neumožňuje sdílení vlastnictví nebo prodloužení doby života.Pokud volaný vytvoří instanci typu shared_ptr z obyčejného ukazatele, tato nová instance typu shared_ptr bude nezávislá na původním ukazateli a nebude tento základní prostředek spravovat.Tuto možnost použijte, pokud kontrakt mezi volajícím a volaným jasně určuje, že volajícímu zůstane vlastnictví po dobu života instance typu shared_ptr.

  • Pokud se rozhodujete jak předat instanci typu shared_ptr, zjistěte, zda volaný musí sdílet vlastnictví základního prostředku.„Vlastník“ je objekt nebo funkce, která může základní prostředek zachovat naživu tak dlouho, dokud jej potřebuje.Pokud volající musí zaručit, že volaný může prodloužit dobu života ukazatele nad rámec své (funkce) doby života, použijte první možnost.Pokud není důležité, zda volaný prodlouží dobu života, použijte předání odkazem a nechte jej volaného zkopírovat nebo ne.

  • Pokud potřebujete pomocné funkci udělit přístup k základnímu ukazateli a víte, že tento ukazatel pouze použije a vrátí se před vrácením volající funkce, tato funkce nemusí sdílet vlastnictví základního ukazatele.K tomuto ukazateli má přístup jen během doby života instance typu shared_ptr volajícího.V tomto případě je bezpečné předat instanci typu shared_ptr odkazem nebo předat obyčejný ukazatel nebo odkaz na základní objekt.Předání tímto způsobem mírně zlepšuje výkon a může také lépe pomoci vyjádřit záměr programu.

  • Někdy, například pro typ std:vector<shared_ptr<T>>, bude pravděpodobně nutné předat každou instanci typu shared_ptr tělu výrazů lambda nebo objektu pojmenované funkce.Pokud výraz lambda nebo funkce tento ukazatel neukládá, předejte instanci typu shared_ptr odkazem, abyste zabránili volání kopie konstruktoru pro každý prvek.

Následující příklad ukazuje, jak typ shared_ptr přetěžuje různé operátory porovnání, což umožňuje porovnání ukazatelů na paměť, která je vlastněna instancemi typu 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; 

Viz také

Koncepty

Chytré ukazatele (moderní verze jazyka C++)