Was ist der richtige Weg, um einen bewegten Container wiederzuverwenden?
std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);
// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize
container.push_back(2);
assert(container.size() == 1 && container.front() == 2);
Nach dem, was ich im C ++ 0x-Standardentwurf gelesen habe; ver3 scheint der richtige Weg zu sein, da sich ein Objekt nach dem Verschieben in a befindet
"Sofern nicht anders angegeben, werden solche weggezogenen Objekte in einen gültigen, aber nicht spezifizierten Zustand versetzt."
Ich habe nie einen Fall gefunden, in dem es "anders angegeben" ist.
Ich finde ver3 zwar ein bisschen umständlich und hätte ver1 sehr bevorzugt, obwohl vec3 eine zusätzliche Optimierung ermöglichen kann, aber andererseits leicht zu Fehlern führen kann.
Ist meine Annahme richtig?
c++
c++11
move-semantics
Ronag
quelle
quelle
clear
, da es keine Voraussetzungen hat (und somit kein Vertrauen in den Zustand des Objekts).std::vector
Implementierung, die einen Zeiger auf seine Größe gespeichert hat (scheint albern, aber legal). Wenn Sie sich von diesem Vektor entfernen, bleibt der Zeiger möglicherweise NULL. Danach schlägt derclear
Fehler fehl.operator=
könnte auch scheitern.Antworten:
Aus Abschnitt 17.3.26 der Spezifikation "gültiger, aber nicht spezifizierter Zustand":
Daher ist das Objekt live. Sie können jeden Vorgang ausführen, für den keine Vorbedingung erforderlich ist (es sei denn, Sie überprüfen die Vorbedingung zuerst).
clear
hat zum Beispiel keine Voraussetzungen. Und es wird das Objekt in einen bekannten Zustand zurückversetzen. Also einfach löschen und wie gewohnt verwenden.quelle
clear
ist der Aufruf gültig. 2) Während der Behälter war in einem unbestimmten Zustand, Aufrufclear
setzt den Behälter in einen bestimmten Zustand , weil es Nachbedingungen in der Norm (§23.2.3 Tabelle 100) beauftragt hat.std::vector<T>
hat eine Klasseninvariante,push_back()
die immer gültig ist (solange sieT
istCopyInsertable
).Das Objekt befindet sich in einem gültigen, aber nicht definierten Zustand. Dies bedeutet im Grunde, dass der genaue Zustand des Objekts zwar nicht garantiert ist, aber gültig ist und als solche garantiert, dass Mitgliedsfunktionen (oder Nicht-Mitgliedsfunktionen) funktionieren, solange sie nicht abhängig sind auf dem Objekt mit einem bestimmten Zustand.
Die
clear()
Member-Funktion hat keine Voraussetzungen für den Status des Objekts (außer dass sie natürlich gültig ist) und kann daher bei verschobenen Objekten aufgerufen werden. Andererseitsfront()
hängt zum Beispiel davon ab, dass der Container nicht leer ist und daher nicht aufgerufen werden kann, da nicht garantiert wird, dass er nicht leer ist.Daher sollten sowohl ver2 als auch ver3 in Ordnung sein.
quelle
front()
nur fürstd::array
und auch dort nicht in der Tabelle angegeben.front()
are ist*a.begin()
, §23.2.1 / 6 sagt " Wenn der Container leer ist, dannbegin() == end()
" und §24.2.1 / 5 sagt " Die Bibliothek nimmt niemals an, dass Vergangenheit- Die Endwerte sind dereferenzierbar. " Folglich denke ich, dass die Voraussetzungen dafürfront()
abgeleitet werden können, obwohl dies sicherlich klarer gemacht werden könnte.Ich glaube nicht, dass Sie mit einem verschobenen Objekt ALLES tun können (außer es zu zerstören).
Können Sie nicht
swap
stattdessen alle Vorteile des Umzugs nutzen, sondern den Container in einem bekannten Zustand belassen?quelle
std::swap
enthält zwei Verschiebungszuweisungen, wobei die Ziele dieser Zuweisungen von Werten verschoben werden. Das zählt für mich als "etwas mit einem verschobenen Objekt tun"