tl; dr: Ja, das Verschieben von a macht std::vector<T, A>
die Iteratoren möglicherweise ungültig
Der häufigste Fall (mit vorhanden std::allocator
) ist, dass keine Ungültigmachung stattfindet, es jedoch keine Garantie gibt und das Wechseln von Compilern oder sogar das nächste Compiler-Update dazu führen kann, dass sich Ihr Code falsch verhält, wenn Sie sich darauf verlassen, dass Ihre Implementierung die Iteratoren derzeit nicht ungültig macht.
Zuweisung bei Umzug :
Die Frage, ob std::vector
Iteratoren nach der Verschiebungszuweisung tatsächlich gültig bleiben können, hängt mit der Allokatorerkennung der Vektorvorlage zusammen und hängt vom Allokatortyp (und möglicherweise den jeweiligen Instanzen davon) ab.
In jeder Implementierung, die ich gesehen habe, macht die Verschiebungszuweisung einer std::vector<T, std::allocator<T>>
1 Iteratoren oder Zeiger nicht ungültig. Es gibt jedoch ein Problem, wenn es darum geht, dies zu nutzen, da der Standard einfach nicht garantieren kann, dass Iteratoren für eine Verschiebungszuweisung einer std::vector
Instanz im Allgemeinen gültig bleiben , da der Container Allokator-fähig ist.
Benutzerdefinierte Zuweiser haben möglicherweise den Status. Wenn sie sich bei der Zuweisung von Verschiebungen nicht ausbreiten und nicht gleich vergleichen, muss der Vektor Speicher für die verschobenen Elemente mithilfe seines eigenen Zuweisers zuweisen.
Lassen:
std::vector<T, A> a{};
std::vector<T, A> b;
b = std::move(a);
Nun wenn
std::allocator_traits<A>::propagate_on_container_move_assignment::value == false &&
std::allocator_traits<A>::is_always_equal::value == false &&
( möglicherweise ab c ++ 17 )
a.get_allocator() != b.get_allocator()
Dann b
wird neuer Speicher zugewiesen und Elemente von verschobena
nacheinander in diesen Speicher , wodurch alle Iteratoren, Zeiger und Referenzen ungültig werden.
Der Grund ist, dass die Erfüllung der obigen Bedingung 1 die Zuordnung des Allokators bei Containerumzug verbietet. Daher müssen wir uns mit zwei verschiedenen Instanzen des Allokators befassen. Wenn diese beiden Allokatorobjekte jetzt weder immer gleich ( 2. ) noch tatsächlich gleich vergleichen, haben beide Allokatoren einen unterschiedlichen Status. Ein Allokator ist x
möglicherweise nicht in der Lage, den Speicher eines anderen Allokators y
mit einem anderen Status freizugeben, und daher kann ein Container mit Allokator x
nicht einfach Speicher von einem Container stehlen, der seinen Speicher über zugewiesen hat y
.
Wenn sich der Allokator bei der Verschiebungszuweisung ausbreitet oder wenn beide Allokatoren gleich sind, wird eine Implementierung sehr wahrscheinlich nur b
eigene a
Daten erstellen, da sie sicher sein kann, den Speicher ordnungsgemäß freizugeben.
1 :std::allocator_traits<std::allocator<T>>::propagate_on_container_move_assignment
undstd::allocator_traits<std::allocator<T>>::is_always_equal
beide sind typdefs fürstd::true_type
(für alle nicht spezialisiertenstd::allocator
).
On-Move-Bau :
std::vector<T, A> a{};
std::vector<T, A> b(std::move(a));
Der Verschiebungskonstruktor eines Allokator-fähigen Containers verschiebt seine Allokator-Instanz aus der Allokator-Instanz des Containers, aus dem der aktuelle Ausdruck verschoben wird. Auf diese Weise wird die ordnungsgemäße Freigabefähigkeit sichergestellt, und der Speicher kann (und wird) gestohlen werden, da die Bewegungskonstruktion (mit Ausnahme von std::array
) eine konstante Komplexität aufweisen muss.
Hinweis: Es gibt noch keine Garantie dafür, dass Iteratoren auch für Verschiebungskonstruktionen gültig bleiben.
Beim Tausch :
Es ist einfach zu fordern, dass die Iteratoren von zwei Vektoren nach einem Swap gültig bleiben (jetzt nur auf den jeweiligen Swap-Container zeigen), da das Swapping nur dann ein definiertes Verhalten aufweist, wenn
std::allocator_traits<A>::propagate_on_container_swap::value == true ||
a.get_allocator() == b.get_allocator()
Wenn sich die Allokatoren beim Auslagern nicht ausbreiten und wenn sie nicht gleich sind, ist das Auslagern der Container in erster Linie ein undefiniertes Verhalten.
a_iter
jetzt auf ein Element verwiesen wird,b
nachdema
es verschoben wurde.