Warum ist es falsch, std :: auto_ptr <> mit Standardcontainern zu verwenden?

217

Warum ist die Verwendung std::auto_ptr<>mit Standardbehältern falsch ?

Uhall
quelle
5
Auf jeden Fall eine +1, weil ich gesehen habe, dass so viele Leute das falsch verstanden haben. Es ist eine gute Frage.
Twokats
Bitte lesen Sie auch den entsprechenden Artikel. Diese Frage wird hier von der anderen Seite betrachtet. Kann hilfreich sein, um mehr über auto_ptr- und STL-Container zu erfahren. stackoverflow.com/questions/8630552/…
Nickolay
1
movesemantisch und unique_ptrwurden entwickelt, um die damit verbundenen Probleme zu vermeiden auto_ptr. In C ++ 03 war die Sprache nicht leistungsfähig genug, um eine solche Klasse zu schreiben auto_ptr, die sich in allen Szenarien korrekt und sicher verhält, da der Compiler und die Sprache nicht in der Lage waren, l- und r-Werte zu unterscheiden, sodass einige "Hacks" verwendet wurden, um das gewünschte Verhalten zu erzielen meistens.
Phil 1970
Schöner Artikel: STL-Container und Auto_ptrs - Warum sie sich nicht mischen quantstart.com/articles/…
alfC

Antworten:

124

Der C ++ - Standard besagt, dass ein STL-Element "kopierkonstruierbar" und "zuweisbar" sein muss. Mit anderen Worten, ein Element muss zugewiesen oder kopiert werden können und die beiden Elemente sind logisch unabhängig. std::auto_ptrerfüllt diese Anforderung nicht.

Nehmen Sie zum Beispiel diesen Code:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

Um diese Einschränkung zu überwinden, sollten Sie die Verwendung std::unique_ptr, std::shared_ptroder std::weak_ptrintelligente Zeiger oder den Boost - Äquivalente , wenn Sie C ++ nicht 11. Hier ist die Dokumentation zur Boost-Bibliothek für diese intelligenten Zeiger.

Kevin
quelle
7
Sie sollten auch die Boost-Zeiger-Container berücksichtigen, wenn Sie keinen gemeinsamen Besitz benötigen.
Me22
4
unique_ptrDas Kopieren ist ebenfalls nicht zulässig, sodass bestimmte STL-Vorgänge nur dann ordnungsgemäß funktionieren, wenn sie die Verschiebungssemantik verwenden können.
Mike Weller
4
"Um diese Einschränkung zu überwinden, sollten Sie std::unique_ptrFolgendes verwenden :": Diese Klassenvorlage kann nur aufgrund der Verschiebungssemantik existieren (ihre Spezifikation erfordert rWertreferenzen), daher ist grundsätzlich C ++ 11 erforderlich. Der C ++ 11-Standard besagt jedoch (und verwandt) nicht mehr, dass ein STL-Elementtyp "kopierkonstruierbar" und "zuweisbar" sein muss. bewegungskonstruierbar und bewegungszuweisbar zu sein, reicht aus. In der Tat sind unique_ptrInstanzen nur bewegungskonstruierbar und verschiebungszuweisbar. Aber auto_ptrInstanzen auch! Infolgedessen können Sie in C ++ 11 das tun, auto_ptrwas Sie können unique_ptr.
Marc van Leeuwen
@MarcvanLeeuwen, es sei denn, Sie resetund releasenach Bedarf
Ratschenfreak
2
@ Ratchetfreak: Hmm, ich verstehe nicht. Was? "es sei denn du resetund release", ich sehe nicht, wie das auf irgendetwas in meinem Kommentar zutrifft. Beachten Sie, dass beide auto_ptrund unique_ptrbeide Methoden haben und in beiden Fällen dasselbe tun.
Marc van Leeuwen
66

Die Kopiersemantik von auto_ptrist nicht mit den Containern kompatibel.

Insbesondere werden beim Kopieren in ein auto_ptranderes Objekt nicht zwei gleiche Objekte erstellt, da eines seinen Besitz des Zeigers verloren hat.

Insbesondere auto_ptrbewirkt das Kopieren eines, dass eine der Kopien den Zeiger loslässt. Welche davon im Container verbleibt, ist nicht definiert. Daher können Sie zufällig den Zugriff auf Zeiger verlieren, wenn Sie auto_ptrsin den Containern speichern .

Frank Krueger
quelle
39

Zwei super ausgezeichnete Artikel zu diesem Thema:

Laser
quelle
Weil ich denke, dass er sich in den letzten fast zwei Jahren wahrscheinlich mit dem vorliegenden Problem befasst hat.
Welpe
27
@DeadMG: Ja, du bist richtig. Aber das war nicht mein Ziel. Wenn irgendwann jemand zu diesem Thread kommt und etwas darüber lernen möchte auto_ptr, sind diese Links hilfreich, da bin ich mir sicher.
Lazer
Es gibt viele Duplikate, die neuer sind.
Welpe
8
@DeadMG: Diese Frage wurde nicht als Duplikat geschlossen und kann daher erweitert werden. Lazer sagte, was hier vorher nicht gesagt wurde. Ich denke, er ist zufällig gekommen.
Sebastian Mach
Die Erklärungen im zweiten Link, die das Problem nach dem Anruf analysieren sort(), sind klarer als alle Antworten hier.
Chaosink
17

Die STL-Container müssen in der Lage sein, die darin gespeicherten Elemente zu kopieren, und müssen so ausgelegt sein, dass das Original und die Kopie gleichwertig sind. Auto-Pointer-Objekte haben einen völlig anderen Vertrag, wobei durch das Kopieren eine Eigentumsübertragung entsteht. Dies bedeutet, dass Container mit auto_ptr je nach Verwendung ein seltsames Verhalten aufweisen.

Es gibt eine detaillierte Beschreibung dessen, was in Effective STL (Scott Meyers) Punkt 8 schief gehen kann, und eine nicht so detaillierte Beschreibung in Effective C ++ (Scott Meyers) Punkt 13.

Garth Gilmour
quelle
12

STL-Container speichern Kopien der enthaltenen Artikel. Wenn ein auto_ptr kopiert wird, wird der alte ptr auf null gesetzt. Viele Containermethoden sind durch dieses Verhalten fehlerhaft.

Dustin Getz
quelle
Aber wenn Sie unique_ptr verwenden, erhalten Sie so ziemlich das Gleiche, da nur ein unique_ptr das Eigentum an dem Objekt haben kann?
Tracer
2
@Tracer kann unique_ptrwie jedes richtige C ++ 11-Objekt das Eigentum an seiner Ressource nur übertragen, wenn es verschoben oder zugewiesen wird. Dadurch wird sichergestellt, dass der Programmierer absichtlich einen std::move(sourceObject)oder einen temporären Wert übergeben muss , anstatt einen l-Wert zu übergeben und ihn unbeabsichtigt / unvorhersehbar mutieren zu lassen die Kopieraufgabe ... die, wie hier ausführlich betont, ein Kernproblem von war auto_ptr.
underscore_d
4

Die Norm C ++ 03 (ISO-IEC 14882-2003) besagt in Abschnitt 20.4.5 Absatz 3:

[...] [ Hinweis: [...] auto_ptr erfüllt nicht die CopyConstructible- und Assignable-Anforderungen für Standard Library-Containerelemente. Das Instanziieren eines Standard Library-Containers mit auto_ptr führt daher zu einem undefinierten Verhalten. - Endnote ]

Der C ++ 11-Standard (ISO-IEC 14882-2011) besagt in Anhang D.10.1 Absatz 3:

[...] Hinweis: [...] Instanzen von auto_ptr erfüllen die Anforderungen von MoveConstructible und MoveAssignable, jedoch nicht die Anforderungen von CopyConstructible und CopyAssignable. - Endnote]

Die Norm C ++ 14 (ISO-IEC 14882-2014) besagt in Anhang C.4.2 Anhang D: Kompatibilitätsmerkmale:

Änderung : Die Klassenvorlagen auto_ptr, unary_function und binary_function, die Funktionsvorlagen random_shuffle und die Funktionsvorlagen (und ihre Rückgabetypen) ptr_fun, mem_fun, mem_fun_ref, bind1st und bind2nd sind nicht definiert.
Begründung : Ersetzt durch neue Funktionen.
Auswirkung auf die ursprüngliche Funktion : Gültiger C ++ 2014-Code, der diese Klassenvorlagen und Funktionsvorlagen verwendet, kann in diesem internationalen Standard möglicherweise nicht kompiliert werden.

Bitek
quelle