Skip to content

Latest commit

 

History

History
134 lines (91 loc) · 3.6 KB

File metadata and controls

134 lines (91 loc) · 3.6 KB

Verschiebe-Semantik / Move Semantics

Zurück


Quellcode


Inhalt


Allgemeines

Die Erweiterung einer Klasse von der Kopier-Konstruktion (dies schließt den Kopier-Konstruktor und den Zuweisungsoperator ein) hin zur Verschiebe-Konstruktion (dies wiederum schließt den Verschiebe-Konstruktor und die Verschiebe-Wertzuweisung ein) kann dem dazugehörigen Quellcode entnommen werden.

Ausschnitt:

01: BigData::BigData(BigData&& data) noexcept {  // move c'tor
02: 
03:     m_data = data.m_data;   // shallow copy
04:     m_size = data.m_size;
05:     data.m_data = nullptr;  // reset source object, ownership has been moved
06:     data.m_size = 0;
07: }

Man beachte, dass das Objekt data – also das durch eine Referenz / einen Aliasnamen an den verschiebenden Konstruktor übergebene Objekt – sich nach nach dem Methodenaufruf in dem so genannten „Moved-From”-Zustand befindet.

An einem Objekt im „Moved-From”-Zustand lassen sich alle vorhandenen Methoden aufrufen, es kommt nicht zu einem Absturz – aber vermutlich auch nicht zu den Ergebnissen, die man erwartet hätte.

An einem Objekt im „Moved-From”-Zustand lassen sich zwei Vorgänge durchführen:

  • Man kann es zerstören
  • Man kann es neu zuweisen

Realisierung

Prinzipiell kann die Move-Semantik auf dreierlei Weisen realisiert werden:

  • Straightforward, also Realisierung ohne direktes Entwurfsmuster,
  • mit zwei Hilfsmethoden cleanup und moveFrom - so genannte Primitive / minimalistisches Entwurfsmuster oder
  • auf Basis des Copy-Swap-Idioms.

Notwendigkeit des Schlüsselworts noexcept

Man beachte die Notwendigkeit des Schlüsselworts noexcept bei der Definition des Move-Konstruktors.

Das folgende Beispiel führt zu unterschiedlichen Ausführungen in Abhängigkeit vom Vorhandensein des noexcept-Schlüsselworts:

01: void test() {
02: 
03:     std::vector<BigData> vec;
04:     vec.push_back(BigData(10, 1));
05:     vec.push_back(BigData(20, 2));
06: }

Ausgabe:

move c'tor
move c'tor
move c'tor

oder

move c'tor
move c'tor
copy c'tor

Fehlt das noexcept-Schlüsselwort, verwendet das STL-Containerobjekt vom Typ std::vector den Kopierkonstruktor, wenn intern der Datenpuffer neu auszurichten ist!


„Rule of Three”, „Rule of Five” und „Rule of Zero”

Rule of Three:

  • Copy constructor: X(const X&)
  • Copy assignment: X& operator=(const X&)
  • Destructor: ~X()

Rule of Five:

  • Copy constructor: X(const X&)
  • Copy assignment: X& operator=(const X&)
  • Move constructor: X(X&&) noexcept
  • Move assignment: X& operator=(X&&) noexcept
  • Destructor: ~X()

Rule of Zero:

  • Es dürfen keine Zeiger vorhanden sein, die mit new allokiert wurden.
  • Verwenden Sie Container Klassen der STL.
  • Verwenden Sie Smart Pointer Variablen.

In diesen Fällen benötigt man keine Realisierung der Rule of Three oder Rule of Five, da der Compiler an Hand der Standardklassen die für diese Klassen passenden Kopier- und Verschiebeoperationen generiert. Deklarieren oder definieren Sie dann keine Operationen der Rule of Three oder Rule of Five für Ihre Klasse.


Zurück