Realizacja std::move
zasadniczo wygląda następująco:Dlaczego polecenie std :: move pobiera odniesienie do przodu?
template<typename T>
typename std::remove_reference<T>::type&&
move(T&& t)
{
return static_cast<typename std::remove_reference<T>::type&&>(t);
}
Należy zauważyć, że parametr std::move
jest uniwersalnym odniesienia (znany również jako odwołanie przekierowania, ale nie jesteśmy spedycja tutaj). Oznacza to, że można std::move
zarówno lwartościami i rvalues:
std::string a, b, c;
// ...
foo(std::move(a)); // fine, a is an lvalue
foo(std::move(b + c)); // nonsense, b + c is already an rvalue
Ale ponieważ cały sens std::move
jest do oddania do rvalue, dlaczego jesteśmy nawet dozwolony std::move
rvalues? Czy nie miałoby większego sensu, gdyby std::move
akceptował tylko wartości l?
template<typename T>
T&&
move(T& t)
{
return static_cast<T&&>(t);
}
Następnie bezsensowne wyrażenie std::move(b + c)
spowodowałoby błąd podczas kompilacji.
Powyższa implementacja std::move
byłaby również znacznie łatwiejsza do zrozumienia dla początkujących, ponieważ kod robi dokładnie to, co wydaje się robić: Zajmuje lwartość i zwraca wartość rurn. Nie musisz rozumieć uniwersalnych odniesień, referencyjnych zwijania i funkcji meta.
Dlaczego więc został std::move
przeznaczony do przyjmowania zarówno wartości l, jak i wartości r?
Moje przypuszczenie jest takie, że kiedy piszesz kod, aby poruszać rzeczy dookoła, nie chcesz ciągle myśleć, czy twoje zmienne to l-wartości, czy r-wartości, po prostu chcesz to zrobić. – sim642
Ponieważ jest zaprojektowany do rzucania zarówno wartości bezwzględnej, jak i rwartościowej bezwarunkowo. –
@ 6502 To pytanie lub jego szczegóły są bardziej przydatne dla programisty biblioteki niż dla programisty aplikacji. Programista aplikacji może po prostu zadzwonić do std :: move(); i zabrać się za pracę. Oczywiście należy zrozumieć, że przeniesienie zmiennej lokalnej spowodowałoby unieważnienie stanu. W przeciwnym razie nic nie złamie tutaj głowy. – Jagannath