std :: auto_ptr bis std :: unique_ptr

185

Mit dem neuen Standard (und Teilen, die bereits in einigen Compilern verfügbar sind) soll der neue Typ std::unique_ptrein Ersatz für sein std::auto_ptr.

Überlappt sich ihre Verwendung genau (damit ich meinen Code global suchen / ersetzen kann (nicht, dass ich dies tun würde, aber wenn ich es tun würde)) oder sollte ich mir einiger Unterschiede bewusst sein, die beim Lesen der Dokumentation nicht erkennbar sind?

Auch wenn es sich um einen direkten Ersatz handelt, warum sollte man ihm einen neuen Namen geben, anstatt nur den zu verbessern std::auto_ptr?

Martin York
quelle

Antworten:

219

Sie können kein globales Suchen / Ersetzen durchführen, da Sie ein auto_ptr(mit bekannten Konsequenzen) kopieren können , aber ein unique_ptrkann nur verschoben werden. Alles was so aussieht

std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p; 

muss zumindest so werden

std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p);

Wie für andere Unterschiede, unique_ptrkann Arrays korrekt behandeln (es wird aufgerufen delete[], während auto_ptrversucht wird, aufzurufen delete.

Cubbi
quelle
101
Auf der anderen Seite führt das Suchen / Ersetzen nur zu Kompilierungsfehlern. Soweit ich sehen kann, wird der Code nicht stillschweigend unterbrochen. Es ist also sicher, wenn Sie die Kompilierungsfehler anschließend manuell beheben
Jalf
7
@jalf: In der Tat kann ich mir kein Gegenbeispiel vorstellen, das mit auto_ptrs und UB mit unique_ptrs gut definiert wäre.
Cubbi
1
Es scheint also, dass unique_ptr eine Erweiterung von auto_ptr ist: Array unterstützen und Mehrdeutigkeiten beseitigen
Baiyan Huang
92

std::auto_ptrund std::unique_ptrsind in einigen Fällen inkompatibel und in anderen ein Rückgang des Ersatzes. Kein Suchen / Ersetzen ist also nicht gut genug. Nach einem Suchen / Ersetzen sollten die Kompilierungsfehler jedoch alles außer seltsamen Eckfällen beheben. Für die meisten Kompilierungsfehler muss a hinzugefügt werden std::move.

  • Funktionsumfangsvariable:
    100% kompatibel, solange Sie sie nicht als Wert an eine andere Funktion übergeben.
  • Rückgabetyp:
    nicht 100% kompatibel, aber 99% kompatibel scheint nicht falsch zu sein.
  • Funktionsparameter nach Wert:
    100% kompatibel mit einer Einschränkung, unique_ptrs muss durch einen std::moveAufruf geleitet werden. Dieser ist einfach, da sich der Compiler beschwert, wenn Sie es nicht richtig machen.
  • Funktionsparameter als Referenz:
    100% kompatibel.
  • Klassenmitgliedsvariable:
    Diese ist schwierig. std::auto_ptrs Kopiersemantik ist böse. Wenn die Klasse das Kopieren nicht zulässt, std::unique_ptrwird die Ersetzung verringert. Wenn Sie jedoch versucht haben, der Klasse eine angemessene Kopiersemantik zu geben, müssen Sie den std::auto_ptrBehandlungscode ändern . Dies ist einfach, da sich der Compiler beschwert, wenn Sie es nicht richtig machen. Wenn Sie das Kopieren einer Klasse mit einem std::auto_ptrMitglied ohne speziellen Code erlaubt haben , dann schämen Sie sich und viel Glück.

Zusammenfassend std::unique_ptrist eine ungebrochene std::auto_ptr. Zum Zeitpunkt der Kompilierung sind Verhaltensweisen nicht zulässig, bei denen bei der Verwendung von a häufig Fehler aufgetreten sind std::auto_ptr. Wenn Sie also std::auto_ptrmit der nötigen Sorgfalt vorgehen, sollte der Wechsel std::unique_ptrzu einfach sein. Wenn Sie sich auf std::auto_ptrdas seltsame Verhalten verlassen haben, müssen Sie Ihren Code trotzdem umgestalten.

deft_code
quelle
8
+1 für "Sie müssen Ihren Code trotzdem umgestalten". auto_ptrs sind nur gut für das, wofür 20.4.5 / 3 sagt, dass sie gut sind.
Cubbi
8
Lassen Sie mich hinzufügen, dass Sie auf jeden Fall auto_ptr durch unique_ptr in Ihrem Code ersetzen und die Kompilierungsfehler beheben sollten. Sie wären überrascht, wie viele Fehler dies aufdecken wird.
Bartosz Milewski
36

SO VIEL ICH WEISS, unique_ptr ist kein direkter Ersatz. Der Hauptfehler, den es behebt, ist die implizite Übertragung des Eigentums.

std::auto_ptr<int> a(new int(10)), b;
b = a; //implicitly transfers ownership

std::unique_ptr<int> a(new int(10)), b;
b = std::move(a); //ownership must be transferred explicitly

Auf der anderen Seite unique_ptrwerden völlig neue Funktionen haben: Sie können in Containern gelagert werden.

Onkel Bens
quelle
8
Scott Meyers erwähnte in seinem "Effective C ++" (3. Ausgabe) Punkt 13 (Seite 64) auch, dass STL-Container ein "normales" Kopierverhalten erfordern, sodass Container von auto_ptrnicht zulässig sind.
Qiang Xu
31

Herb Sutter hat eine nette Erklärung zu GotW # 89 :

Was ist mit auto_ptr los?auto_ptr wird am gemeinnützigsten als ein tapferer Versuch charakterisiert, ein unique_ptr zu erstellen, bevor C ++ die Bewegungssemantik hatte. auto_ptr ist jetzt veraltet und sollte nicht in neuem Code verwendet werden.

Wenn Sie auto_ptr in einer vorhandenen Codebasis haben, versuchen Sie, wenn Sie die Möglichkeit haben, ein globales Suchen und Ersetzen von auto_ptr durch unique_ptr durchzuführen. Die überwiegende Mehrheit der Anwendungen funktioniert auf die gleiche Weise und kann einen oder zwei Fehler, von denen Sie nicht wussten, dass Sie sie hatten, aufdecken (als Fehler beim Kompilieren) oder (stillschweigend) beheben.

Mit anderen Worten, während ein globales Suchen und Ersetzen Ihren Code vorübergehend "beschädigen" kann, sollten Sie es trotzdem tun: Es kann einige Zeit dauern, bis die Kompilierungsfehler behoben sind, aber Sie sparen auf lange Sicht viel mehr Ärger.

ValarDohaeris
quelle
Toller Link. Vielen Dank!
fotNelton