Das obige Beispiel erzeugt die nächste Ausgabe:
%Vor%Fragen:
PS Ich habe gerade überprüft, und die Objekte sind tatsächlich wie erwartet platziert (der erste geht auf die Position 0 im Vektor, und der zweite geht auf die Position 1 im Vektor)
PPS Wenn es darauf ankommt, verwende ich gcc 4.3 und kompiliere das Programm wie folgt:
%Vor%Ich habe Ihr Beispiel leicht umgeschrieben:
%Vor%const
aus dem Move-Konstruktor entfernt. std::move
aus push_back
entfernt (es ist überflüssig). foo
eingefügt. Für mich druckt das ähnlich wie Ihr Code:
%Vor%
- Warum wird der erste Destruktor ausgeführt (wird aber nicht ausgeführt für den 2. Objekt)?
Der 2. Destruktor wird für das 2. Objekt an der mit // 1
markierten Zeile ausgeführt. Dies ist die Zerstörung des temporären A()
am Ende des zweiten Aufrufs von push_back
.
- Warum wird das 2. Objekt bewegt, vor dem Verschieben des 1. Objekts ausgeführt? Objekt?
Hinweis: Für mich wird das 1. Objekt kopiert, nicht verschoben, mehr dazu unten.
Antwort: Ausnahmesicherheit.
Erklärung: Während dieser push_back
entdeckt der Vektor, dass er einen vollen Puffer (von eins) hat und einen neuen Puffer mit Platz für zwei erstellen muss. Es erstellt den neuen Puffer. Dann verschiebt das zweite Objekt in diesen Puffer (am Ende davon). Wenn diese Konstruktion eine Ausnahme auslöst, ist der ursprüngliche Puffer immer noch intakt und das vector
bleibt unverändert. Andernfalls werden die Elemente vom ersten Puffer zum zweiten Puffer verschoben oder kopiert (also das erste Element verschieben / kopieren).
Wenn A
einen noexcept
move-Konstruktor hat, wird ein move
verwendet, um ihn vom alten in den neuen Puffer zu verschieben. Wenn der Move-Konstruktor jedoch nicht noexcept
ist, wird ein copy
verwendet. Dies ist wiederum für Ausnahmesicherheit. Wenn die Bewegung vom alten zum neuen Puffer fehlschlagen kann, muss der alte Puffer intakt bleiben, damit der vector
in seinen ursprünglichen Zustand zurückversetzt werden kann.
Wenn ich noexcept
zu Ihrem Move-Konstruktor hinzufüge:
Dann ist meine Ausgabe:
%Vor% Beachten Sie, dass die mit // 2
markierte Zeile die Zerstörung des ersten Elements aus dem alten Puffer ist, nachdem es in den neuen Puffer verschoben wurde.
- Warum werden am Ende zwei Destruktoren für jedes Objekt ausgeführt?
Dies markiert die Zerstörung von vector
und somit die Zerstörung jedes Elements von vector
.
Die vernünftige Verwendung von reserve
löst die Hälfte Ihres Problems: Ссылка indem Sie die Anzahl der unerwarteten Bewegungen reduzieren ( dass du nicht explizit darum bittest)
Vergessen Sie auch nicht, dass der Destruktor des Temps weiterhin auslöst, nachdem in den Vektor verschoben wurde. Deshalb müssen Sie sicherstellen, dass die Temp auch nach dem Verschieben / Konstruieren im gesunden , zerstörbaren Zustand bleibt.
%Vor%Ein Verschiebungskonstruktor "zerstört" das verschobene Objekt nicht.
%Vor%Die Ausgabe ergibt:
%Vor%Tags und Links c++ c++11 object-lifetime