Was kann ich mit einem verschobenen Objekt tun?

138

Definiert der Standard genau, was ich mit einem Objekt tun kann, wenn es verschoben wurde? Früher dachte ich, dass alles, was Sie mit einem verschobenen Objekt tun können, darin besteht, es zu zerstören, aber das würde nicht ausreichen.

Nehmen Sie zum Beispiel die Funktionsvorlage, swapwie sie in der Standardbibliothek definiert ist:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Offensichtlich muss es möglich sein, verschobenen Objekten zuzuweisen, da sonst die Zeilen 2 und 3 fehlschlagen würden. Was kann ich sonst noch mit verschobenen Objekten tun? Wo genau finde ich diese Angaben im Standard?

(Übrigens, warum ist es T c = std::move(a);statt T c(std::move(a));in Zeile 1?)

Fredoverflow
quelle

Antworten:

53

Verschobene Objekte befinden sich in einem nicht angegebenen, aber gültigen Zustand. Dies deutet darauf hin, dass das Objekt möglicherweise nicht mehr viel kann, aber alle seine Mitgliedsfunktionen immer noch ein definiertes Verhalten aufweisen sollten - einschließlich operator=- und alle seine Mitglieder in einem definierten Zustand - und dass es dennoch zerstört werden muss. Der Standard enthält keine spezifischen Definitionen, da er für jeden UDT eindeutig ist. Möglicherweise finden Sie jedoch Spezifikationen für Standardtypen. Einige wie Container sind relativ offensichtlich - sie verschieben nur ihren Inhalt und ein leerer Container ist ein genau definierter gültiger Zustand. Grundelemente ändern das verschobene Objekt nicht.

Randnotiz: Ich glaube, es ist T c = std::move(a)so, dass die Funktion fehlschlägt, wenn der Verschiebungskonstruktor (oder der Kopierkonstruktor, wenn keine Verschiebung bereitgestellt wird) explizit ist.

Hündchen
quelle
26
Nicht alle Mitgliedsfunktionen weisen ein definiertes Verhalten auf. Nur diejenigen ohne Vorbedingungen. Zum Beispiel möchten Sie wahrscheinlich nicht zu pop_backeiner eingefahrenen aus vector. Aber Sie können sicher herausfinden, ob es ist empty().
Howard Hinnant
6
@ Howard Hinnant: pop_backVon einem leeren vectorhat sowieso undefiniertes Verhalten, aus dem Speicher, also bin ich mir ziemlich sicher, dass pop_backvon einem bewegten Vektor, der undefiniertes Verhalten zeigt, konsistent ist.
Welpe
12
Wir diskutieren von verschobenen Objekten. Keine Objekte, von denen bekannt ist, dass sie sich in einem leeren Zustand befinden. Verschobene Objekte haben einen nicht angegebenen Status (sofern natürlich nicht anders angegeben). [lib.types.movedfrom]
Howard Hinnant
5
@Howard Nicht spezifiziert, aber gültig, pop_backverhält sich also immer noch wie bei jedem gültigen Vektor (kann es sogar ein leerer Vektor sein).
Christian Rau
1
Was bedeutet in diesem Zusammenhang nicht spezifiziert und gültig?
Ankur S
114

17.6.5.15 [lib.types.movedfrom]

Objekte von Typen, die in der C ++ - Standardbibliothek definiert sind, können aus (12.8) verschoben werden. Verschiebungsoperationen können explizit angegeben oder implizit generiert werden. Sofern nicht anders angegeben, werden solche weggezogenen Objekte in einen gültigen, aber nicht spezifizierten Zustand versetzt.

Wenn sich ein Objekt in einem nicht angegebenen Zustand befindet, können Sie jede Operation an dem Objekt ausführen, für die keine Voraussetzungen vorliegen. Wenn es eine Operation mit Vorbedingungen gibt, die Sie ausführen möchten, können Sie diese Operation nicht direkt ausführen, da Sie nicht wissen, ob der nicht angegebene Status des Objekts die Voraussetzungen erfüllt.

Beispiele für Operationen, die im Allgemeinen keine Voraussetzungen haben:

  • Zerstörung
  • Zuordnung
  • konst Beobachter wie get, empty,size

Beispiele für Operationen, die im Allgemeinen Voraussetzungen haben:

  • Dereferenzierung
  • Pop zurück

Diese Antwort wird jetzt im Videoformat hier angezeigt: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s

Howard Hinnant
quelle
1
Aber ich könnte die Voraussetzungen einfach wie bei jedem anderen Objekt überprüfen, oder?
Fredoverflow
6
@FredOverflow Solange diese Prüfungen selbst keine Voraussetzungen haben, natürlich.
Christian Rau
1
@ Chris: Aber wie unterscheidet sich das von einem normalen, nicht verschobenen Objekt?
Fredoverflow
2
Möglicherweise sollte dies eine separate Frage sein, aber bedeutet das: Wenn ich eine Zeichenfolge mit char* buffer;und mit int length;Mitgliedern habe, muss mein Verschiebungskonstruktor / meine Zuweisungszuweisung den Wert von beiden austauschen (oder festlegen)? Oder wäre es in Ordnung sein, wenn die Länge nicht näher bezeichnet wurde (was bedeutet , dass emptyund sizesinnlose Werte zurück)?
Onkel Bens
3
@ 6502: Du machst keinen Sinn. Eine C ++ 03-Klasse verstößt nicht gegen den C ++ 0x-Standard, da ein generierter Verschiebungsfaktor gegen den Standard verstoßen würde. Und C ++ 03-Code würde diese Klasse nicht verschieben, sodass es keinen Grund gibt, einen Verschiebungscode zu generieren.
MSalters