Move Semantics i Pass-by-Rvalue-Reference w przeciążonej arytmetyce
Koduję małą numeryczną bibliotekę analityczną w C ++. Próbowałem zaimplementować za pomocą najnowszych funkcji C ++ 11, w tym semantykę ruchu. Rozumiem dyskusję i najlepszą odpowiedź w następującym poście:C ++ 11 rvalues i zamieszanie w semantyce przenoszenia (instrukcja return) , ale jest jeden scenariusz, w którym wciąż próbuję owinąć głowę.
Mam klasę, zadzwońT
, który jest w pełni wyposażony w przeciążonych operatorów. Mam także konstruktorów do kopiowania i przenoszenia.
T (const T &) { /*initialization via copy*/; }
T (T &&) { /*initialization via move*/; }
Mój kod klienta w dużym stopniu korzysta z operatorów, dlatego staram się zapewnić, aby złożone wyrażenia arytmetyczne czerpały maksymalne korzyści z semantyki ruchu. Rozważ następujące:
T a, b, c, d, e;
T f = a + b * c - d / e;
Bez semantyki ruchu moi operatorzy tworzą nową zmienną lokalną za pomocą konstruktora kopii za każdym razem, więc jest w sumie 4 kopie. Miałem nadzieję, że z semantyką ruchu mogę zredukować to do 2 kopii plus kilka ruchów. W wersji nawiasowej:
T f = a + (b * c) - (d / e);
każdy z(b * c)
i(d / e)
musi utworzyć tymczasowy w zwykły sposób z kopią, ale wtedy byłoby wspaniale, gdybym mógł wykorzystać jeden z tych tymczasowych do zgromadzenia pozostałych wyników tylko z ruchami.
Korzystając z kompilatora g ++, byłem w stanie to zrobić, ale podejrzewam, że moja technika może nie być bezpieczna i chcę w pełni zrozumieć dlaczego.
Oto przykładowa implementacja operatora dodawania:
T operator+ (T const& x) const
{
T result(*this);
// logic to perform addition here using result as the target
return std::move(result);
}
T operator+ (T&& x) const
{
// logic to perform addition here using x as the target
return std::move(x);
}
Bez wezwaństd::move
, wtedy tylkoconst &
zawsze wywoływana jest wersja każdego operatora. Ale podczas używaniastd::move
jak powyżej, kolejna arytmetyka (po najgłębszych wyrażeniach) jest wykonywana za pomocą&&
wersja każdego operatora.
Wiem, że RVO można zahamować, ale na bardzo kosztownych obliczeniowo rzeczywistych problemach wydaje się, że zysk nieznacznie przewyższa brak RVO. Oznacza to, że w ciągu milionów obliczeń otrzymuję bardzo małe przyspieszenie, gdy uwzględniamstd::move
. Choć szczerze mówiąc, jest wystarczająco szybki bez. Naprawdę chcę po prostu w pełni zrozumieć semantykę tutaj.
Czy jest jakiś guru C ++, który chętnie poświęci czas na wyjaśnienie, w prosty sposób, czy i dlaczego moje użycie std :: move jest tutaj złe? Z góry bardzo dziękuję.