Widziałem to tutaj: Move Constructor wywołujący klasę podstawową Move Constructor
Czy ktoś mógłby wyjaśnić:
- różnica między
std::move
istd::forward
, najlepiej z kilkoma przykładami kodu? - Jak łatwo o tym pomyśleć i kiedy użyć których
c++
c++11
perfect-forwarding
aCuria
źródło
źródło
move
gdy chcesz przenieść wartość iforward
kiedy chcesz użyć idealnego przekazywania. To nie jest fizyka jądrowa;)Odpowiedzi:
std::move
pobiera obiekt i pozwala traktować go jako tymczasowy (wartość r). Chociaż nie jest to wymaganie semantyczne, zwykle funkcja akceptująca odwołanie do wartości r unieważni ją. Kiedy widziszstd::move
, oznacza to, że wartość obiektu nie powinna być później używana, ale nadal możesz przypisać nową wartość i nadal jej używać.std::forward
ma pojedynczy przypadek użycia: rzutowanie parametru funkcji z szablonu (wewnątrz funkcji) na kategorię wartości (lwartość lub rwartość), której obiekt wywołujący użył do przekazania. Pozwala to na przekazywanie argumentów r-wartości jako r-wartości, a l-wartości jako l-wartości, co jest schematem nazywanym „przekazywaniem perfekcyjnym”.Aby zilustrować :
Jak wspomina Howard, istnieją również podobieństwa, ponieważ obie te funkcje są po prostu rzutowane na typ referencyjny. Ale poza tymi konkretnymi przypadkami użycia (które obejmują 99,9% użyteczności rzutów referencyjnych rvalue), powinieneś użyć
static_cast
bezpośrednio i napisać dobre wyjaśnienie tego, co robisz.źródło
std::forward
„s tylko przypadek użycia jest idealne przekazywanie argumentów funkcji. Spotkałem się z sytuacjami, w których chcę idealnie przekazać inne rzeczy, takie jak elementy składowe obiektów.Obie
std::forward
istd::move
są niczym innym jak odlewami.Powyższe rzutuje wyrażenie l-
x
wartości typu X na wyrażenie r-wartości typu X (dokładnie xwartość).move
może również akceptować wartość r:w tym przypadku jest to funkcja tożsamości: przyjmuje wartość r typu X i zwraca wartość r typu X.
Dzięki
std::forward
niemu możesz w pewnym stopniu wybrać miejsce docelowe:Rzuca wyrażenie l-
x
wartości typu X na wyrażenie typu Y. Istnieją ograniczenia dotyczące tego, czym może być Y.Y może być dostępną bazą X lub odwołaniem do podstawy X. Y może oznaczać X lub odniesienie do X. Nie można odrzucać kwalifikatorów cv
forward
, ale można dodać kwalifikatory cv. Y nie może być typem, który można jedynie zamienić z X, z wyjątkiem dostępnej konwersji Base.Jeśli Y jest odwołaniem do lwartości, wynik będzie wyrażeniem lwartości. Jeśli Y nie jest odniesieniem do lwartości, wynik będzie wyrażeniem rvalue (a dokładniej xvalue).
forward
może przyjąć argument rvalue tylko wtedy, gdy Y nie jest odniesieniem do lwartości. Oznacza to, że nie można rzutować wartości r na lwartość. Dzieje się tak ze względów bezpieczeństwa, ponieważ często prowadzi to do zawieszania się odniesień. Ale rzutowanie rvalue na rvalue jest w porządku i dozwolone.Jeśli spróbujesz określić Y jako coś, co jest niedozwolone, błąd zostanie przechwycony w czasie kompilacji, a nie w czasie wykonywania.
źródło
std::forward
, to czy po wykonaniu tej funkcji mogę użyć tego obiektu? Zdaję sobie sprawę, że w przypadkustd::move
jest to niezdefiniowane zachowanie.move
: stackoverflow.com/a/7028318/576911 uzyskaćforward
, jeśli przechodzą w lwartością Twój API powinien reagować tak, jakby odbiera lwartością. Zwykle oznacza to, że wartość nie zostanie zmieniona. Ale jeśli jest to wartość inna niż stała l, Twój interfejs API mógł ją zmodyfikować. Jeśli przekażesz rvalue, zwykle oznacza to, że Twój interfejs API mógł się z niej przenieść, a zatem zastosowanie miałoby stackoverflow.com/a/7028318/576911 .std::forward
służy do przekazywania parametru dokładnie w taki sposób, w jaki został przekazany do funkcji. Tak jak pokazano tutaj:Kiedy używać std :: forward do przekazywania argumentów?
Użycie
std::move
oferuje obiekt jako rvalue, aby ewentualnie dopasować konstruktor przenoszenia lub funkcję akceptującą rvalues. Robi tak,std::move(x)
nawet jeślix
sama w sobie nie jest wartością r.źródło