Zastanawiam się, w jakich przypadkach sensowne jest stosowanie semantyki ruchu podczas przeciążania operatora + i/lub operatora + =. Chociaż jest to wyjaśnione w this question, jak można to zrobić, nie mogę się skupić na tym, dlaczego to zrobiłem. Rozważmy operator + =. Jeśli po prostu przekazuję prawą stronę przez odniesienie i dokonuję odpowiednich zmian na obiekcie po lewej stronie, i tak nie ma niepotrzebnych kopii. Więc wracamy do tego samego punktu: czy poruszenie semantyką byłoby w takim przypadku korzystne?Czy ma sens stosowanie semantyki przeniesienia dla operatora + i/lub operatora + =?
Odpowiedz
Tak i nie.
operator semantyka + =
ruch nie zawsze są pomocne dla operator+=
w ogóle, bo jesteś już modyfikując argument po lewej stronie (this
), więc masz już środków do pracy z najbardziej czasów.
Mimo to optymalizacja może być tego warta. Wyobraź sobie implementację std::string
, której domyślny konstruktor nie alokuje żadnej pamięci. Wtedy std::string::operator+=(std::string&&)
może po prostu ukraść zasoby z RHS. Albo wyobraź sobie, że bufor RHS jest wystarczająco duży, aby pomieścić wszystko, ale LHS nie jest, wtedy jeśli możesz użyć bufora RHS, to jesteś złoty: po prostu zamień i wstań.
Może warto, ale trzeba się uczyć. Dlatego:
T& T::operator+=(T const&)
: zawsze obecnyT& T::operator+=(T&&)
: umożliwienie semantykę przesunięta, gdy ma to sens
operator +
Tutaj zawsze jest przydatna (pod warunkiem, że mówimy o klasach dla których przydatne są semantyki ruchu).
Rzecz polega na tym, że operator+
produkuje tymczasowo (na niebiesko), więc generalnie musi utworzyć zasoby dla tego tymczasowego. Jeśli jednak uda im się je ukraść, a nie tworzyć, jest to z pewnością tańsze.
Jednak nie trzeba dostarczyć wszystkie przeciążeń:
T operator+(T const&, T const&)
T operator+(T&&, T const&)
T operator+(T const&, T&&)
T operator+(T&&, T&&)
(wymagana ujednoznacznienie)
Nie można ponownie wykorzystać ten sam podstęp, który operator=
użyj i twórz tymczasowe prawo w podpisie funkcji (przez wzięcie jednego argumentu za pomocą kopii). Jeśli typ jest ruchomy, konstruktor ruchu zostanie wywołany, w przeciwnym razie będzie to konstruktor kopiowania, ale ponieważ i tak potrzebujesz tymczasowego, bez utraty wydajności.
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(T const& left, T right) { right += left; return right; } // commutative
inline T operator+(T left, T&& right) { left += right; return left; } // disambiguation
Nie wiele zyskać (3 zamiast 4), ale cóż, wezmę co mogę!
Oczywiście dla napisu, operator+
nie jest przemienny (dlatego jest to złe przeciążenie), więc rzeczywista implementacja drugiego przeciążenia wymagałaby metody prepend
.
EDIT: po Move semantics and operator overloading wydaje się, że byłem nieco zbyt entuzjastyczny. Kradzież z odpowiedzią na Ben Voigt, otrzymujemy:
inline T operator+(T left, T const& right) { left += right; return left; }
inline T operator+(const T& left, T&& right) { right += left; return right; }
Z drugiej strony, wydaje się to tylko pracować dla operacji przemiennych; -
nie działa w ten sposób, ale prawdopodobnie można go zaadaptować, /
i %
z drugiej strony ...
Lepiej rób 'right + = left; return right; 'sprawić, że po powrocie rozważy" right "jako wartość r. –
@ JohannesSchaub-litb: Czy mogę przypuszczać, że mówisz o ostatnim przypadku? Zastanawiałem się też nad tym i czy warto przeciążać 'T && T :: operator +() i &'. –
Mówię o wszystkich trzech przypadkach. Jeśli 'T' ma konstruktor ruchu, możesz go użyć, zwracając odpowiednio" left "lub" right ". Tak jak jest teraz z twoim kodem, jeśli 'operator + =' zwraca 'T &', zawsze skopiujesz parametr do wartości zwracanej zamiast go przenosić. –
Jeśli dodajesz dwa ciągi, wektory itd., Których nie możesz "przenieść", nie ma to sensu. Ale jeśli dodajesz, mówisz o połączonych listach, gdzie dołączanie listy jest prawdopodobnie operatorem O (1), jeśli chcesz poświęcić prawą stronę, to ma to sens.
- 1. Czy VBA ma trójskładnikowego operatora?
- 2. Czy VHDL ma operatora trójskładnikowego?
- 3. Czy maszynopis ma przeciążenie operatora?
- 4. Czy ma sens stosowanie inline keyword z szablonami?
- 5. ma int mieć operatora ==
- 6. Dlaczego nie ma operatora [] dla std :: list?
- 7. Definicja „==” operatora dla podwójnego
- 8. Czy Scala ma operatora podobnego do `$` Haskella?
- 9. Czy ma sens stosowanie "LIMIT 1" w zapytaniu "SELECT 1 ..."?
- 10. Czy ma sens stosowanie std :: uninitialized_fill() z dowolnym przydziałem?
- 11. C++ Lambda nie ma operatora()
- 12. Przeciążanie operatora dla manipulatorów
- 13. Typ OCaml operatora plusa
- 14. Czy powinienem używać operatora + = zamiast operatora + do łączenia std :: string?
- 15. Czy zmienna static constexpr ma sens?
- 16. Implementacja operatora konwersji dla wskaźnika
- 17. Tworzenie `` `operatora mocy dla Scala?
- 18. Jakie jest znaczenie operatora &?
- 19. Konsekwentna implementacja operatora równości C#
- 20. StringFormat dla operatora Java Boolean
- 21. Czy haskell ma operatora splat jak python/ruby?
- 22. Jak działa "object.new"? (Czy Java ma operatora .new?)
- 23. Język C: znaczenie operatora "#"?
- 24. Semantyka odniesienia operatora warunkowego
- 25. Alternatywa dla „w” operatora dla zagnieżdżonych list
- 26. Przeciążanie operatora <i operatora> w tej samej klasie
- 27. Zapamiętywanie składni potrójnego operatora
- 28. Czy C# "??" Czy wątek operatora jest bezpieczny?
- 29. Styl kodowania PHP dla operatora Nie
- 30. Nadużywanie operatora przecinka
Generalnie zły pomysł na przeciążenie operatorów. Ponieważ: ** 1) ** jeśli oczywiście jest to dobry przypadek, prawdopodobnie jest to biblioteka już dla ciebie. ** 2) ** jeśli nie jest to oczywiście dobry przypadek, to prawdopodobnie bardzo źle to zrobić. – enobayram
@enobayram sprawiają, że jest to funkcja "dopisz", jeśli jesteś chybiony wokół przeciążonych operatorów. Teraz wciąż możesz odpowiedzieć na pytanie. –
@obobayram, to nie ma żadnego sensu. Zgodnie z tą logiką, generalnie złym pomysłem jest pisanie kodu kiedykolwiek. – TonyK