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ę.

questionAnswers(3)

yourAnswerToTheQuestion