-
Notifications
You must be signed in to change notification settings - Fork 0
04 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());
}
};- 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
}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
}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: 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"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.