Freigeben über


Gewusst wie: Erstellen und verwenden Sie shared_ptr Instanzen

Der shared_ptr-Typ ist ein intelligenter Zeiger in der C++-Standardbibliothek, die soll für Szenarien, in denen muss mehr als ein Besitzer kann die Lebensdauer des Objekts im Arbeitsspeicher verwalten.Nachdem Sie shared_ptr initialisieren, das Sie es kopieren können, führen Sie es als Wert in den Funktionsargumenten, und weisen Sie es auf andere shared_ptr-Instanzen zu.Alle Instanzen verweisen auf das gleiche Objekt frei, und geben Zugriff auf einen "diesem Kontrollblock" Inkremente und Dekrementieren, die der Verweiszähler, wenn neue shared_ptr hinzugefügt wird, den Gültigkeitsbereich verlässt oder zurückgesetzt werden.Wenn der Verweiszähler null erreicht, löscht der Kontrollblock die Speicherressource und selbst.

Die folgende Abbildung zeigt mehrere shared_ptr-Instanzen, die zu einer Speicheradresse zeigen.

Freigegebener Zeiger

Beispiel

Wenn möglich, die make_shared (<memory>)-Funktion verwenden Sie, um shared_ptr zu erstellen, wenn die Speicherressource zum ersten Mal erstellt wird.make_shared ist ausnahmesich.Sie verwendet den gleichen Aufruf, den Speicher für den Kontrollblock und die Ressource zuzuordnen und reduziert dadurch den Konstruktionsmehraufwand.Wenn Sie nicht make_shared verwenden, müssen Sie einen expliziten neuen Ausdruck verwenden, um das Objekt zu erstellen, bevor Sie es an shared_ptr-Konstruktor übergeben.Im folgenden Beispiel werden verschiedene Möglichkeiten veranschaulicht, shared_ptr zusammen mit einem neuen Objekt zu deklarieren und zu initialisieren.


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

Im folgenden Beispiel wird gezeigt, wie shared_ptr-Instanzen deklariert und initialisiert, die auf gemeinschaftlichem Eigentum eines Objekts akzeptieren, das bereits für ein anderes shared_ptr zugeordnet wurde.Angenommen, sp2 initialisiertes shared_ptr ist.

//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 ist auch in den Containern der Standardvorlagenbibliothek (STL) hilfreich, wenn Sie die Algorithmen verwenden, die Elemente kopieren.Sie können Elemente in shared_ptr umschließen und kopieren es dann in andere Container, unter der Voraussetzung, dass der zugrunde liegende Arbeitsspeicher, solange Sie ihn benötigen, und nicht mehr gültig ist.Das folgende Beispiel zeigt, wie der replace_copy_if Algorithmus auf shared_ptr als Generatorinstanziierung in einem Vektor verwendet.

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;
});

Sie können dynamic_pointer_cast, static_pointer_cast und const_pointer_cast verwenden, um shared_ptr umzuwandeln.Diese Funktionen dynamic_cast ähneln, static_cast und const_cast-Operatoren.Das folgende Beispiel zeigt, wie der abgeleiteten Typ jedes Elements in einem Vektor von shared_ptr von Basisklassen testet und dann die Elemente und die Informationen zu sie kopiert.

    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;
    });

Sie können shared_ptr an eine andere Funktion folgendermaßen übergeben:

  • Führen Sie shared_ptr durch einen Wert.Dies ruft den Kopierkonstruktor auf, erhöht den Verweiszähler und macht die Aufgerufene einen Besitzer.Es gibt eine kleine Menge an Mehraufwand in diesem Vorgang, der möglicherweise signifikant ist abhängig davon, wie viele shared_ptr-Objekten Sie übergeben.Verwenden Sie diese Option, wenn der Codevertrag (bedeutet oder explizit) zwischen dem Aufrufer und dem Aufgerufenen erfordert, dass die Aufgerufenen einen Besitzer ist.

  • Führen Sie shared_ptr durch Verweis oder es.In diesem Fall wird der Verweiszähler nicht erhöht, und die Aufgerufene kann für den Zeiger zugreifen, solange der Aufrufer nicht den Gültigkeitsbereich verlässt.Oder, der Aufgerufene kann festlegen, dass shared_ptr basierend auf den Verweis zu erstellen, und ein freigegebener Besitzer darin zu werden.Verwenden Sie diese Option, wenn der Aufrufer keine Kenntnis der Aufgerufenen hat oder wenn Sie shared_ptr übergeben und den Kopiervorgang aus Leistungsgründen vermeiden möchten müssen.

  • Führen Sie den Zeiger oder einen Verweis auf das zugrunde liegende Objekt.Dadurch kann der Aufgerufene, um das Objekt zu verwenden, können jedoch nicht zur Kapitalbeteiligung oder erweitert die Lebensdauer.Wenn der Aufgerufene shared_ptr vom unformatierten Zeiger erstellt, ist shared_ptr neue von der Vorlage unabhängig und steuert nicht die zugrunde liegende Ressource.Verwenden Sie diese Option, wenn der Vertrag zwischen dem Aufrufer und dem Aufgerufenen eindeutig angibt, dass der Aufrufer den Besitz der shared_ptr Lebensdauer beibehält.

  • Wenn Sie entscheiden, wie shared_ptr, führt bestimmen, ob der Aufgerufene Kapitalbeteiligung der zugrunde liegenden Ressource muss.Ein "Besitzer" ist ein Objekt oder eine Funktion, die aktiv halten kann die zugrunde liegende Ressource für, solange sie erforderlich sind.Wenn der Aufrufer muss sicherstellen, dass der Aufgerufene die Lebensdauer des Zeigers über der seiner Lebensdauer (der Funktion hinaus) erweitern kann, verwenden Sie die erste Option.Wenn Sie sich nicht bestimmen möchten, ob der Aufgerufene die Lebensdauer erweitert, dann ist Durchlauf Verweis und Aufgerufener ihn kopieren oder nicht.

  • Wenn Sie einen Hilfsfunktionszugriff zum zugrunde liegenden Zeiger geben müssen und Sie wissen, dass die Hilfsfunktion nur den Zeiger verwendet und zurückgibt, bevor die aufrufende Funktion zurückgibt, wird, wird die Funktion nicht muss Kapitalbeteiligung des zugrunde liegenden Zeigers ausführt.Sie muss auf den Mauszeiger innerhalb der Lebensdauer shared_ptr des Aufrufers nur zugreifen.In diesem Fall ist es sicher, shared_ptr als Verweis zu übergeben, oder übergeben Sie den unformatierten Zeiger oder einen Verweis auf das zugrunde liegende Objekt.Das Übergeben dieser Methode stellt eine etwas höhere Leistung und hilft Ihnen auch, die Programmierung Absicht auszudrücken.

  • Manchmal beispielsweise in std:vector<shared_ptr<T>>, müssen Sie möglicherweise alle shared_ptr zu einem Lambda-Ausdrucks-Text oder einem benannten Funktionsobjekt übergeben.Wenn Lambda oder Funktion nicht den Mauszeiger speichert, dann führen Sie shared_ptr mit Hinweis auf vermeiden, den Kopierkonstruktor für jedes Element aufzurufen.

Im folgenden Beispiel wird gezeigt, wie shared_ptr verschiedene Vergleichsoperatoren überladen werden, um Zeigervergleiche für den Arbeitsspeicher zu aktivieren, der von shared_ptr gehört, wird als Beispiel.


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

Siehe auch

Konzepte

Intelligente Zeiger modernes (C++)