Warum wird auto_ptr nicht mehr unterstützt?

91

Ich habe auto_ptrgehört, dass es in C ++ 11 veraltet ist. Was ist der Grund dafür?

Auch ich würde gerne den Unterschied zwischen auto_ptrund kennen shared_ptr.

brett
quelle
Mögliches Duplikat von Ist auto_ptr veraltet?
Malat

Antworten:

90

Der direkte Ersatz für auto_ptr(oder das, was einem sowieso am nächsten kommt) ist unique_ptr. Was das "Problem" betrifft, ist es ziemlich einfach: auto_ptrÜberträgt das Eigentum, wenn es zugewiesen wird. unique_ptrüberträgt auch das Eigentum, aber dank der Kodifizierung der Bewegungssemantik und der Magie der Wertreferenzen kann dies wesentlich natürlicher geschehen. Es "passt" auch wesentlich besser zum Rest der Standardbibliothek (obwohl ein Teil davon fairerweise darauf zurückzuführen ist, dass der Rest der Bibliothek geändert wurde, um die Verschiebungssemantik zu berücksichtigen, anstatt immer kopiert werden zu müssen).

Die Namensänderung ist auch (IMO) eine willkommene - auto_ptrsagt nicht wirklich viel darüber aus, was sie zu automatisieren versucht, wohingegen unique_ptreine ziemlich vernünftige (wenn auch knappe) Beschreibung dessen, was bereitgestellt wird.

Jerry Sarg
quelle
24
Nur ein Hinweis zum auto_ptrNamen: auto schlägt automatisch wie in der automatischen Variablen vor und bezieht sich auf eine Sache, auto_ptrdie Folgendes bewirkt: Zerstören der verwalteten Ressource in ihrem Destruktor (wenn sie außerhalb des Gültigkeitsbereichs liegt).
Vincenzo Pii
13
Weitere Informationen: Hier ist die offizielle Begründung für die Ablehnungauto_ptr : open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
Howard Hinnant
@ HowardHinnant interessantes Dokument! In gewissem Sinne ist es seltsam, dass wenn std :: sort () eine Spezialisierung für std :: unique_ptr hat, die Verschiebungssemantik nach Bedarf verwendet wird. Ich frage mich, warum std :: sort () nicht auf std :: auto_ptr spezialisiert werden kann, um das im Dokument erwähnte Kopierproblem zu beheben. Danke im Voraus.
Hei
2
@Hei: std::sorthat keine Spezialisierung für unique_ptr. Stattdessen wurde es neu spezifiziert, um niemals zu kopieren. So funktioniertauto_ptr eigentlich mit der Moderne . C ++ 98/03 ist hier jedoch nur ein Beispielalgorithmus: Jeder generische Algorithmus (vom Standard bereitgestellt oder vom Benutzer geschrieben), der davon ausgeht, dass die Kopiersyntax eine Kopiersemantik aufweist, weist bei Verwendung wahrscheinlich einen Laufzeitfehler auf , da er sich stillschweigend bewegt mit Kopie - Syntax. Das Problem ist viel größer als nur . sortsortauto_ptrauto_ptrsort
Howard Hinnant
35

Ich fand die vorhandenen Antworten großartig, aber aus dem PoV der Zeiger. IMO, eine ideale Antwort sollte die perspektivische Antwort des Benutzers / Programmierers haben.

Das erste zuerst (wie Jerry Coffin in seiner Antwort angedeutet hat)

  • auto_ptr kann je nach Situation durch shared_ptr oder unique_ptr ersetzt werden

shared_ptr: Wenn Sie Bedenken haben, Ressourcen / Speicher freizugeben UND wenn Sie mehr als eine Funktion haben, die das Objekt AT-DIFFERENT mal verwenden könnte, dann gehen Sie zu shared_ptr.

Stellen Sie sich bei DIFFERENT-Times eine Situation vor, in der das Objekt-ptr in mehreren Datenstrukturen gespeichert ist und später darauf zugegriffen wird. Ein weiteres Beispiel sind natürlich mehrere Threads.

unique_ptr: Wenn Sie nur Speicher freigeben und der Zugriff auf das Objekt SEQUENTIAL ist, wählen Sie unique_ptr.

Mit SEQUENTIAL meine ich, dass zu jedem Zeitpunkt von einem Kontext aus auf das Objekt zugegriffen wird. ZB ein Objekt, das erstellt und unmittelbar nach der Erstellung durch den Ersteller verwendet wurde. Nach der Erstellung wird das Objekt in der FIRST- Datenstruktur gespeichert . Dann wird entweder das Objekt nach der ONE-Datenstruktur zerstört oder in die SECOND- Datenstruktur verschoben .

In dieser Zeile werde ich Shared / Unique _ptr als Smart-Pointer bezeichnen. (auto_ptr ist auch ein Smart-Pointer, ABER aufgrund von Designfehlern, für die sie veraltet sind und auf die ich in den nächsten Zeilen hinweisen werde, sollten sie nicht mit Smart-Pointer gruppiert werden.)

Der wichtigste Grund, warum auto_ptr zugunsten von smart-pointer veraltet war, ist die Zuweisungssemantik. Wenn dies nicht der Fall gewesen wäre, hätten sie alle neuen Extras der Verschiebungssemantik zu auto_ptr hinzugefügt, anstatt sie zu verwerfen. Da die Zuweisungssemantik am wenigsten beliebt war, wollten sie, dass diese Funktion wegfällt. Da jedoch Code geschrieben ist, der diese Semantik verwendet (die das Standardkomitee nicht ändern kann), mussten sie stattdessen auto_ptr loslassen es zu ändern.

Über den Link: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

Art der von unqiue_ptr unterstützten Zuweisungen

  • Bewegungszuordnung (1)
  • Nullzeiger zuweisen (2)
  • Typ-Cast-Zuordnung (3)
  • Kopierauftrag (gelöscht!) (4)

Von: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

Art der von auto_ptr unterstützten Zuweisungen

  • Kopieraufgabe (4) Schuldiger

Nun zu dem Grund, warum die Kopieraufgabe selbst so unbeliebt war, habe ich diese Theorie:

  1. Nicht alle Programmierer lesen Bücher oder Standards
  2. auto_ptr verspricht Ihnen das Eigentum an dem Objekt
  3. Die Klausel little- * (Wortspiel beabsichtigt) des auto_ptr, die nicht von allen Programmierern gelesen wird, ermöglicht die Zuweisung eines auto_ptr zu einem anderen und überträgt das Eigentum.
  4. Untersuchungen haben gezeigt, dass dieses Verhalten für 3,1415926535% aller Nutzungen bestimmt ist und in anderen Fällen nicht beabsichtigt ist.

Das unbeabsichtigte Verhalten ist wirklich unbeliebt und daher die Abneigung gegen auto_ptr.

(Für die 3.1415926536% der Programmierer, die absichtlich das Eigentum übertragen möchten, gab C ++ 11 ihnen std :: move (), was ihre Absicht für alle Praktikanten, die den Code lesen und pflegen werden, kristallklar machte.)

Ajeet Ganga
quelle
1
Da Sie niemals möchten, dass zwei auto_ptrWerte auf dasselbe Objekt verweisen (da sie kein gemeinsames Eigentum geben, hinterlässt der erste, der stirbt, dem anderen ein tödliches Erbe; dies gilt auch für die unique_ptrVerwendung), können Sie vorschlagen, was in beabsichtigt war die verbleibenden 96,8584073465% aller Nutzung?
Marc van Leeuwen
Ich kann nicht für alle sprechen, aber ich würde vermuten, sie würden denken , dass der Besitz des Objekts verschoben und NICHT nur dupliziert wird, was falsch ist.
Ajeet Ganga
@AjeetGanga In der folgenden Phrase 'das kleine * (Wortspiel beabsichtigt)' haben Sie als "Wortspiel beabsichtigt" erwähnt. Dieser Satz ist neu für mich und trotzdem habe ich ihn gegoogelt und erfahren, dass es einen Witz gibt, der hier absichtlich gemacht wurde. Was ist das für ein Witz hier? Nur neugierig das zu wissen.
VINOTH ENERGETIC
@AjeetGanga Sie haben wie 'die kleine * (Wortspiel beabsichtigt) Klausel des auto_ptr erwähnt, die nicht von allen Programmierern gelesen wird, die Zuweisung eines auto_ptr zu einem anderen ermöglicht und das Eigentum überträgt'. Angenommen, ich habe zwei Auto-PTRs als a und b zur Ganzzahl. Ich mache die Zuordnung als *a=*b;Hier wird nur der Wert von b nach a kopiert. Ich hoffe, dass das Eigentum an a und b immer noch bei denselben Personen liegt. Sie haben erwähnt, dass das Eigentum übertragen wird. Wie es sein wird?
VINOTH ENERGETIC
@VINOTHENERGETIC Ajeet sprach über das Zuweisen zu einem auto_ptrObjekt selbst. Die Zuordnung zu / von seinem angegebenen Wert hat weder Auswirkungen noch Relevanz für das Eigentum. Ich hoffe du benutzt noch nicht auto_ptr?
underscore_d
23

shared_ptrkann in Behältern gelagert werden. auto_ptrkippen.

Übrigens unique_ptrist wirklich der direkte auto_ptrErsatz, es kombiniert die besten Eigenschaften von beiden std::auto_ptrund boost::scoped_ptr.

Ben Voigt
quelle
11

Noch eine andere Art, den Unterschied zu erklären ...

Funktionell ist C ++ 11 std::unique_ptrdas "Feste" std::auto_ptr: Beide sind geeignet, wenn zu einem beliebigen Zeitpunkt während der Ausführung ein einziger Smart-Pointer-Eigentümer für ein Objekt vorhanden sein sollte, auf das verwiesen wird.

Der entscheidende Unterschied besteht in der Erstellung oder Zuweisung von Kopien von einem anderen nicht ablaufenden Smart Pointer (siehe folgende =>Zeilen):

   std::auto_ptr<T> ap(...);
   std::auto_ptr<T> ap2(get_ap_to_T());   // take expiring ownership
=> std::auto_ptr<T> ap3(ap);  // take un-expiring ownership ala ap3(ap.release());
   ap->xyz;  // oops... can still try to use ap, expecting it to be non-NULL

   std::unique_ptr<T> up(...);
   std::unique_ptr<T> up2(get_up_to_T());   // take expiring ownership
=> std::unique_ptr<T> up3(up);  // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up4(std::move(up));  // EXPLICIT code allowed
=> std::unique_ptr<T> up4(up.release());   // EXPLICIT code allowed

Oben ap3"stiehlt" er leise das Eigentum an *apund verlässt apes auf a nullptr, und das Problem ist, dass dies zu leicht passieren kann, ohne dass der Programmierer über seine Sicherheit nachgedacht hat.

Wenn ein class/ beispielsweise structein std::auto_ptrMitglied hat, wird releasebeim Erstellen einer Kopie einer Instanz der Zeiger der zu kopierenden Instanz angezeigt. Dies ist eine seltsame und gefährlich verwirrende Semantik, da das Kopieren normalerweise nichts ändert. Es ist für den Klassen- / Strukturautor leicht, die Freigabe des Zeigers zu übersehen, wenn er über Invarianten und den Status nachdenkt, und folglich versehentlich zu versuchen, den Smart-Zeiger zu dereferenzieren, während er null ist, oder einfach noch nicht den erwarteten Zugriff / Besitz der referenzierten Daten zu haben.

Tony Delroy
quelle
auto_ptr "stiehlt" leise Besitz +1
camino
3

auto_ptr kann nicht in STL-Containern verwendet werden, da es einen Kopierkonstruktor hat, der die Anforderungen des Containers CopyConstructible nicht erfüllt . unique_ptr implementiert keinen Kopierkonstruktor, daher verwenden Container alternative Methoden. unique_ptr kann in Containern verwendet werden und ist für Standardalgorithmen schneller als shared_ptr.

#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>

using namespace std;

int main() {
  cout << boolalpha;
  cout << "is_copy_constructible:" << endl;
  cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
  cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
  cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;

  vector<int> i_v;
  i_v.push_back(1);
  cout << "i_v=" << i_v[0] << endl;
  vector<int> i_v2=i_v;
  cout << "i_v2=" << i_v2[0] << endl;

  vector< unique_ptr<int> > u_v;
  u_v.push_back(unique_ptr<int>(new int(2)));
  cout << "u_v=" << *u_v[0] << endl;
  //vector< unique_ptr<int> > u_v2=u_v;  //will not compile, need is_copy_constructible == true
  vector< unique_ptr<int> > u_v2 =std::move(u_v);  // but can be moved
  cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;

  vector< shared_ptr<int> > s_v;
  shared_ptr<int> s(new int(3));
  s_v.push_back(s);
  cout << "s_v=" << *s_v[0] << endl;
  vector< shared_ptr<int> > s_v2=s_v;
  cout << "s_v2=" << *s_v2[0] << endl;

  vector< auto_ptr<int> > a_v;  //USAGE ERROR

  return 0;
}

>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
   vector< auto_ptr<int> > a_v;  //USAGE ERROR
           ^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3
edW
quelle