Skip to content

04 Move Semantik

gideon edited this page Oct 24, 2024 · 1 revision

Zusammenfassung der Slides "Move-Semantik in C++"

Hintergrund der Move-Semantik

Move-Semantik wird verwendet, um die Performance zu verbessern, insbesondere beim Umgang mit großen Objekten. Wenn ein Objekt kopiert wird, kann der Kopieraufwand beträchtlich sein. Move-Semantik ermöglicht stattdessen, den Besitz von Ressourcen von einem Objekt zu einem anderen zu übertragen, anstatt sie zu kopieren.

Beispiel einer Klasse mit Kopierkonstruktor:

class RGBAImage {
    size_t m_size;
    std::unique_ptr<uint32_t[]> m_data;
public:
    RGBAImage(const RGBAImage& im) : m_size(im.m_size), m_data(std::make_unique<uint32_t[]>(m_size)) {
        std::copy(im.m_data.get(), im.m_data.get() + m_size, m_data.get());
    }
};

Optimierung bei Datenweitergabe

  • Referenzen (l-value Referenzen) ermöglichen eine effiziente Datenweitergabe an Funktionen, da die Daten nicht kopiert, sondern direkt adressiert werden.
  • Return Value Optimization (RVO) vermeidet unnötige Kopien bei der Rückgabe von Werten aus Funktionen. Der Compiler eliminiert temporäre Objekte, um die Performance zu steigern.
  • r-value Referenzen ermöglichen den Zugriff auf temporäre Objekte und helfen, unnötige Kopien zu vermeiden.

Beispiel zur Rückgabeoptimierung:

struct C {
    C() { std::cout << "std ctor" << std::endl; }
    C(const C& c) { std::cout << "copy ctor" << std::endl; }
};

C foo() {
    return C();
}

int main() {
    C c = foo();  // RVO vermeidet Aufruf des Kopierkonstruktors
}

Wertekategorien

C++ unterscheidet verschiedene Wertekategorien:

  • l-value: Hat Identität, ist jedoch nicht verschiebbar (z. B. Variablen).
  • pr-value (pure right value): Hat keine Identität, ist jedoch verschiebbar (z. B. Literale).
  • x-value (expiring value): Hat Identität und ist verschiebbar (z. B. std::move(c)).

Beispiel zur Unterscheidung:

void test(int& x) { std::cout << "non movable" << std::endl; }
void test(int&& x) { std::cout << "movable" << std::endl; }

int main() {
    int x = 5;
    test(x);  // non movable
    test(5);  // movable
}

Besitzübernahme (Move-Semantik)

Die Idee der Move-Semantik ist es, die Daten eines temporären Objekts vor dessen Zerstörung zu übernehmen. Dadurch werden unnötige Kopien vermieden, was die Performance deutlich verbessert.

Beispiel einer Klasse mit Verschiebekonstruktor und Verschiebeoperator:

class PointVector {
    std::unique_ptr<Point[]> m_array;
    size_t m_size;
public:
    PointVector(PointVector&& v) : m_array(std::move(v.m_array)), m_size(v.m_size) {
        v.m_size = 0;
    }
    PointVector& operator=(PointVector&& v) {
        if (this != &v) {
            m_size = v.m_size;
            v.m_size = 0;
            m_array = std::move(v.m_array);
        }
        return *this;
    }
};

std::move und std::exchange

  • std::move: Ein Typkonvertierungsoperator, der sicherstellt, dass der Compiler den Verschiebekonstruktor oder den Verschiebeoperator anstelle des Kopierkonstruktors verwendet.
  • std::exchange: Wird verwendet, um den Wert eines Objekts durch einen neuen Wert zu ersetzen und den alten Wert zurückzugeben.

Beispiel:

std::string s1 = "hello";
std::string s2 = std::move(s1);  // s1 ist danach leer, s2 enthält "hello"

Rückgabetyp und Move-Semantik

Funktionen können temporäre Objekte zurückgeben, indem sie std::move verwenden. Dadurch kann die Erstellung von temporären Objekten optimiert werden.

Beispiel:

std::string foo(std::string&& s) {
    s += "456";
    return std::move(s);  // Move-Semantik für die Rückgabe
}

Diese Zusammenfassung bietet einen Überblick über die Vorteile und die Anwendung der Move-Semantik in C++. Durch den Einsatz von Move-Semantik können Performance-Verbesserungen erzielt und unnötige Kopien vermieden werden.

Clone this wiki locally