Die C++ Core Guidelines verbinden zwei Empfehlungen für größere Codebasen: ES.56 verlangt einen gezielten Einsatz von std::move, C.67 behandelt Kopien von Basisklassen und Slicing. Grundlage dieses Beitrags ist der offizielle Repository-Stand vom 13. Februar 2018. Die Regeln sind keine neue C++-Sprachversion.
Ein Cast verschiebt noch keine Daten
std::move kennzeichnet ein Objekt als möglichen Ausgangspunkt einer Verschiebeoperation. Der Cast allein leert weder einen Container noch überträgt er einen Zeiger. Erst die nachfolgende Operation entscheidet, ob Daten verschoben, kopiert oder gar nicht verändert werden. Ein sinnvoller Fall ist die Übergabe eines std::unique_ptr an eine Funktion, die dessen Besitz übernimmt.
Bei Rückgabewerten ist ein zusätzlicher Cast oft unnötig. Die historische Guideline empfiehlt return result; statt return std::move(result); für eine lokale Variable. Der zusätzliche Cast kann Return Value Optimization verhindern. Nach einer tatsächlich erfolgten Verschiebeoperation darf unverändert erhaltener Inhalt nicht ohne Grundlage vorausgesetzt werden.
Kopieren als Basisklasse verliert den abgeleiteten Anteil
Slicing entsteht, wenn ein abgeleitetes Objekt als Wert einer Basisklasse kopiert wird. Der zusätzliche Zustand wird nicht Bestandteil dieser Kopie. Das folgende eigene Beispiel zeigt außerdem die Folge für einen virtuellen Aufruf:
struct Base {
virtual ~Base() = default;
virtual int kind() const { return 1; }
};
struct Derived : Base {
int kind() const override { return 2; }
};
int by_value(Base object) { return object.kind(); }
int by_reference(const Base& object) { return object.kind(); }
Für ein Derived-Objekt liefert by_value hier 1, by_reference dagegen 2. Die Kopie ist ein eigenständiges Base-Objekt; die Referenz behält den Bezug zum abgeleiteten Objekt. Das Beispiel wurde mit C++14 kompiliert und geprüft. Es ist kein Benchmark.
C.67 empfiehlt, gewöhnliche Kopien der Basisklasse zu unterbinden und bei Bedarf eine virtuelle clone-Operation vorzusehen. Die Rückgabe eines besitzenden Smart Pointers verlangt einen passenden gemeinsamen Rückgabetyp; unique_ptr<Derived> ist keine kovariante Überschreibung von unique_ptr<Base>.
In Engine- und Editorcode gehören Besitzübertragung und Klassenhierarchien deshalb in die Schnittstellenprüfung. Die Regeln für robuste C++-Schnittstellen behandeln den zugehörigen Vertrag zwischen Modulen. Verlinkt ist bewusst die historische Fassung, nicht der heute veränderliche Stand der Sammlung.

