Gegebene Klasse X
unten (spezielle Memberfunktionen, die nicht explizit definiert sind, sind für dieses Experiment nicht relevant):
Das folgende Programm erstellt einen Vektor von Objekten vom Typ X
und ändert seine Größe, so dass seine Kapazität überschritten wird und die Neuzuweisung erzwungen wird:
Da die Klasse X
einen Verschiebungskonstruktor liefert, würde ich erwarten, dass der vorherige Inhalt des Vektors nach der Neuzuweisung in den neuen Speicher verschoben wird . Ziemlich überraschend, scheint das nicht der Fall zu sein , und die Ausgabe, die ich bekomme, ist:
Warum?
§ 23.3.6.3/14 des C ++ 11 Standards spezifiziert (über die resize()
member Funktion der vector<>
Klassenvorlage):
Hinweise : Wenn eine Ausnahme ausgelöst wird, die nicht vom Move-Konstruktor eines Nicht-
CopyInsertable T
ausgelöst wurde, gibt es keine Effekte .
Mit anderen Worten bedeutet dies, dass X
für CopyInsertable
(was resize()
ist) die anbietet starke Garantie : Entweder gelingt es oder der Zustand des Vektors bleibt unverändert.
Um diese Garantie zu erfüllen, verwenden Implementierungen normalerweise die Kopie -and-swap idiom : Wenn der Kopierkonstruktor von X
auswirft, haben wir den Inhalt des ursprünglichen Vektors noch nicht geändert, daher wird das Versprechen gehalten.
Wenn jedoch der vorherige Inhalt des Vektors in den neuen Speicher verschoben und nicht kopiert wurde und der Verschiebungskonstruktor geworfen hat, hätten wir das Original irreversibel geändert Inhalt des Vektors.
Daher verwenden Implementierungen den Kopierkonstruktor von X
, um den Inhalt des Vektors sicher in einen neuen Speicher zu übertragen , es sei denn, der Verschiebungskonstruktor ist dafür bekannt, nicht zu werfen. In diesem Fall ist er sicher von den vorherigen Elementen abweichen.
Mit einer kleinen Änderung an der Definition von X
's move constructor (Markierung als noexcept
), tatsächlich die Ausgabe des Programms ist jetzt die erwartete .
Denken Sie über die Ausnahmegarantien nach: Wenn es während der Neuzuordnung eine Ausnahme gibt, muss der Vektor unverändert bleiben. Dies kann nur gewährleistet werden, indem die Elemente kopiert und das alte Set beibehalten wird, bis die gesamte Kopie erfolgreich ist.
Nur wenn Sie wissen, dass der Verschiebungskonstruktor nicht geworfen werden kann, können Sie die Elemente sicher an den neuen Ort verschieben. Um dies zu erreichen, deklarieren Sie den Move-Konstruktor noexcept
.
Tags und Links c++ c++11 move-semantics copy-constructor