Move semantics to mechanizm w C++, który umożliwia efektywne przenoszenie zasobów pomiędzy obiektami, a nie ich kopiowanie. Wraz z pojawieniem się C++11 wprowadzono konstruktorzy przenoszący i operatory przypisania, które pozwalają obiektom na przekazywanie swoich zasobów innemu obiektowi bez kosztów związanych z kopiowaniem.
std::move przekształca przekazywany obiekt w rvalue-referencję, sygnalizując, że można bezpiecznie przenieść zasoby. std::forward jest używany w szablonach do zachowania typu wartości (lvalue/rvalue) podczas dalszego przekazywania.
#include <string> #include <vector> #include <iostream> std::vector<std::string> getNames() { std::vector<std::string> v = {"Alice", "Bob", "Charlie"}; return v; // Tutaj zadziała move semantics } int main() { std::vector<std::string> names = getNames(); // Tutaj zawartość getNames() zostanie przeniesiona bez dodatkowego kopiowania }
Czym różni się std::move od konstruktorów przenoszących? Czy jeśli użyję std::move, to zawsze obiekt zostanie przeniesiony?
Odpowiedź:
std::move to tylko rzutowanie na rvalue-referencję, nie wykonuje samo w sobie przeniesienia. Operacja przeniesienia zadziała tylko wtedy, gdy rzeczywiście istnieje zaimplementowany move-konstruktor/operator. W przeciwnym razie dojdzie do kopiowania.
struct A { A() = default; // brak move-konstruktora A(const A&) { std::cout << "Kopiowanie! "; } }; A a1; A a2 = std::move(a1); // Wywołuje kopiowanie, a nie przenoszenie
Historia
-W jednej z systemów finansowych optymalizowano pracę ze stringami, zastępując kopiowanie std::move, ale struktura nie miała zaimplementowanych move-konstruktorów. Kopiowanie pozostawało, wydajność się nie zwiększyła, powstało fałszywe poczucie przyspieszenia kodu.
Historia
-Rozwijający wykonał std::move() nad zmienną, której nadal używał po przeniesieniu. Dane znalazły się w niespójnym stanie, aplikacja regularnie się zawieszała.
Historia
-W serwerowym kodzie biblioteki przyjmowano tymczasowe obiekty przez const referencję, a następnie próbowano std::move(), oczekując przeniesienia. W rezultacie - kopiowanie, nieefektywna praca i zwiększone opóźnienia przy dużych obciążeniach.