it-swarm.com.de

Unterschiede zwischen unique_ptr und shared_ptr

Mögliche Duplikate:
pimpl: shared_ptr oder unique_ptr
Smart Pointer (Boost) erklärt

Könnte jemand die Unterschiede zwischen shared_ptr und unique_ptr erklären?

211
smallB

Diese beiden Klassen sind intelligente Zeiger, was bedeutet, dass sie (in den meisten Fällen) automatisch die Zuordnung des Objekts aufheben, auf das sie zeigen, wenn auf dieses Objekt nicht mehr verwiesen werden kann. Der Unterschied zwischen den beiden besteht darin, wie viele verschiedene Zeiger jedes Typs auf eine Ressource verweisen können.

Bei Verwendung von unique_ptr Kann höchstens ein unique_ptr Auf eine Ressource verweisen. Wenn dieser unique_ptr Zerstört wird, wird die Ressource automatisch zurückgefordert. Da eine Ressource nur einen unique_ptr Enthalten kann, führt jeder Versuch, eine Kopie eines unique_ptr Zu erstellen, zu einem Fehler bei der Kompilierung. Dieser Code ist beispielsweise illegal:

unique_ptr<T> myPtr(new T);       // Okay
unique_ptr<T> myOtherPtr = myPtr; // Error: Can't copy unique_ptr

unique_ptr Kann jedoch mit der neuen Verschiebungssemantik verschoben werden :

unique_ptr<T> myPtr(new T);                  // Okay
unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr

In ähnlicher Weise können Sie Folgendes tun:

unique_ptr<T> MyFunction() {
    unique_ptr<T> myPtr(/* ... */);

    /* ... */

    return myPtr;
}

Diese Redewendung bedeutet "Ich gebe eine verwaltete Ressource an Sie zurück. Wenn Sie den Rückgabewert nicht explizit erfassen, wird die Ressource bereinigt. Wenn Sie dies tun, haben Sie jetzt das ausschließliche Eigentum an dieser Ressource." Auf diese Weise können Sie sich unique_ptr Als sichereren und besseren Ersatz für auto_ptr Vorstellen.

shared_ptr Hingegen ermöglicht es, dass mehrere Zeiger auf eine bestimmte Ressource zeigen. Wenn das allerletzte shared_ptr Einer Ressource zerstört wird, wird die Ressource freigegeben. Dieser Code ist beispielsweise vollkommen legal:

shared_ptr<T> myPtr(new T);       // Okay
shared_ptr<T> myOtherPtr = myPtr; // Sure!  Now have two pointers to the resource.

Intern verwendet shared_ptrReferenzzählung , um zu verfolgen, wie viele Zeiger auf eine Ressource verweisen. Sie müssen also darauf achten, keine Referenzzyklen einzuführen.

Zusamenfassend:

  1. Verwenden Sie unique_ptr, Wenn Sie einen einzelnen Zeiger auf ein Objekt haben möchten, der zurückgefordert wird, wenn dieser einzelne Zeiger zerstört wird.
  2. Verwenden Sie shared_ptr, Wenn Sie mehrere Zeiger auf dieselbe Ressource haben möchten.

Hoffe das hilft!

451
templatetypedef

unique_ptr ist der leichtgewichtige Smart Pointer der Wahl, wenn Sie nur ein dynamisches Objekt haben, für das ein Verbraucher die alleinige (daher "einzigartige") Verantwortung trägt - Vielleicht eine Wrapper-Klasse, die ein dynamisch zugewiesenes Objekt verwalten muss. unique_ptr hat sehr wenig Overhead. Es ist nicht kopierbar, aber beweglich. Sein Typ ist template <typename D, typename Deleter> class unique_ptr;, also hängt es von zwei Template-Parametern ab.

unique_ptr ist auch was auto_ptr wollte im alten C++ sein, konnte es aber aufgrund der Einschränkungen dieser Sprache nicht.

shared_ptr dagegen ist ein ganz anderes tier. Der offensichtliche Unterschied besteht darin, dass viele Verbraucher die Verantwortung für ein dynamisches Objekt teilen können (daher "gemeinsam"), und das Objekt wird nur dann zerstört, wenn alle gemeinsam genutzten Zeiger verschwunden sind. Außerdem können Sie schwache Zeiger beobachten , die auf intelligente Weise informiert werden, wenn der gemeinsame Zeiger, dem sie folgen, verschwunden ist.

Im Inneren, shared_ptr hat noch viel mehr zu bieten: Es gibt einen Referenzzähler, der atomar aktualisiert wird, um die Verwendung in gleichzeitigem Code zu ermöglichen. Außerdem gibt es eine Menge Zuweisungen, eine für einen internen Buchhaltungs-Referenzkontrollblock und eine andere (oft) für das eigentliche Mitgliedsobjekt.

Es gibt aber noch einen weiteren großen Unterschied: Der Typ für gemeinsame Zeiger ist immertemplate <typename T> class shared_ptr;, und das trotz der Tatsache, dass Sie es mit benutzerdefinierten Löschern und mit benutzerdefinierten Zuordnern initialisieren können. Der Deleter und der Allokator werden mithilfe von Type Erasure und Virtual Function Dispatch nachverfolgt, was das interne Gewicht der Klasse erhöht, aber den enormen Vorteil hat, dass verschiedene Arten von gemeinsam genutzten Zeigern vom Typ T alle kompatibel sind, unabhängig von der Lösch- und Zuordnungsdetails. Somit drücken sie das Konzept der "geteilten Verantwortung für T" wirklich aus, ohne den Verbraucher mit den Details zu belasten!

Beide shared_ptr und unique_ptr sollen als Wert übergeben werden (mit der offensichtlichen Beweglichkeitsanforderung für den eindeutigen Zeiger). Sie sollten sich auch keine Sorgen über den Overhead machen, da ihre Macht wirklich verblüffend ist, aber wenn Sie die Wahl haben, bevorzugen Sie unique_ptr und benutze nur shared_ptr wenn Sie wirklich geteilte Verantwortung brauchen.

70
Kerrek SB

nique_ptr
ist ein intelligenter Zeiger, der ausschließlich ein Objekt besitzt.

shared_ptr
ist ein intelligenter Zeiger für das gemeinsame Eigentum. Es ist sowohl copyable als auch movable. Mehrere Smart Pointer-Instanzen können dieselbe Ressource besitzen. Sobald der letzte Smart Pointer, dem die Ressource gehört, den Gültigkeitsbereich verlässt, wird die Ressource freigegeben.

17
Alok Save

Wenn Sie einen Zeiger in einen unique_ptr Einfügen, können Sie nicht mehrere Kopien von unique_ptr Erstellen. Der shared_ptr Enthält einen Referenzzähler, der die Anzahl der Kopien des gespeicherten Zeigers zählt. Bei jedem Kopieren eines shared_ptr Wird dieser Zähler erhöht. Jedes Mal, wenn ein shared_ptr Zerstört wird, wird dieser Zähler dekrementiert. Wenn dieser Zähler 0 erreicht, wird das gespeicherte Objekt zerstört.

8
neodelphi