To pytanie dotyczy std::move(T && t); istnieje również std::move(InputIt first, InputIt last, OutputIt d_first)algorytm związany z std::copy. Zwracam na to uwagę, aby inni nie byli tak zdezorientowani jak ja, kiedy po raz pierwszy skonfrontowałem się z std::moveprzyjęciem trzech argumentów. en.cppreference.com/w/cpp/algorithm/move
W C ++ 11, oprócz konstruktorów kopiowania, obiekty mogą mieć konstruktory ruchów.
(Oprócz operatorów kopiowania przypisania mają także operatory przypisania przeniesienia).
Konstruktor ruchu jest używany zamiast konstruktora kopiowania, jeśli obiekt ma typ „rvalue-reference” ( Type &&).
std::move() jest rzutowaniem, które generuje odwołanie do wartości do obiektu, aby umożliwić poruszanie się z niego.
Jest to nowy sposób C ++ pozwalający uniknąć kopii. Na przykład, używając konstruktora przenoszenia, a std::vectormoże po prostu skopiować swój wewnętrzny wskaźnik do danych do nowego obiektu, pozostawiając przeniesiony obiekt w stanie przeniesionym ze stanu, a zatem nie kopiując wszystkich danych. To byłoby C ++ - poprawne.
Spróbuj googlingu, aby uzyskać semantykę ruchu, wartość rue, doskonałe przekazywanie.
Semantyka Move wymaga, aby przeniesiony obiekt pozostał ważny , co nie jest stanem niepoprawnym. (Uzasadnienie: To wciąż musi
niszczyć
13
@GMan: cóż, musi być w stanie, który jest bezpieczny do zniszczenia, ale, AFAIK, nie musi być przydatny do niczego innego.
Zan Lynx,
8
@ZanLynx: Racja. Zauważ, że biblioteka standardowa wymaga dodatkowo przypisania przeniesionych obiektów, ale dotyczy to tylko obiektów używanych w standardzie, nie jest to ogólny wymóg.
GManNickG
24
-1 „std :: move () jest sposobem C ++ 11 na użycie semantyki move” Proszę to naprawić. std::move()nie jest sposobem używania semantyki ruchów, semantyka ruchów jest wykonywana dla programisty w sposób transparentny. movejest to tylko rzutowanie, które przekazuje wartość z jednego punktu do drugiego, gdzie oryginalna wartość nie będzie już używana.
Manu343726,
15
Poszedłbym dalej std::movesamo w sobie „nic” - ma zerowe skutki uboczne. To tylko sygnalizuje kompilatorowi, że programista nie dba już o to, co stanie się z tym obiektem. tzn. zezwala innym częściom oprogramowania na przemieszczanie się z obiektu, ale nie wymaga przenoszenia. W rzeczywistości odbiorca odwołania do wartości nie musi składać żadnych obietnic dotyczących tego, co zrobi lub nie zrobi z danymi.
Aaron McDaid,
240
1. „Co to jest?”
Chociaż std::move() technicznie jest to funkcja - powiedziałbym, że tak naprawdę nie jest funkcją . Jest to rodzaj konwertera między sposobami, w których kompilator uwzględnia wartość wyrażenia.
2. „Co to robi?”
Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że std::move()tak naprawdę nic nie rusza . Konwertuje wyrażenie od bycia lwartość (takich jak zmiennej o nazwie) do bycia xvalue . Wartość x mówi kompilatorowi:
Możesz mnie ograbić, przenieść wszystko, co trzymam i użyć go gdzie indziej (bo i tak wkrótce mnie zniszczą).
innymi słowy, kiedy używasz std::move(x), pozwalasz kompilatorowi na kanibalizację x. Zatem jeśli x, powiedzmy, ma własny bufor w pamięci - po std::move()kompilacji może zamiast niego posiadać inny obiekt.
Możesz także przejść z prvalue (np. Tymczasowego mijania), ale jest to rzadko przydatne.
3. „Kiedy należy go użyć?”
Innym sposobem na zadanie tego pytania jest: „Po co miałbym kanibalizować zasoby istniejącego obiektu?” cóż, jeśli piszesz kod aplikacji, prawdopodobnie nie będziesz się zbytnio bawić w tymczasowe obiekty tworzone przez kompilator. Zasadniczo robiłbyś to w miejscach takich jak konstruktory, metody operatora, funkcje podobne do algorytmów biblioteki standardowej itp., W których obiekty są często tworzone i niszczone automatycznie. Oczywiście to tylko ogólna zasada.
Typowym zastosowaniem jest „przenoszenie” zasobów z jednego obiektu do drugiego zamiast kopiowania. @Guillaume prowadzi do tej strony, która ma prosty krótki przykład: zamiana dwóch obiektów przy mniejszym kopiowaniu.
template<class T>
swap(T& a, T& b){
T tmp(a);// we now have two copies of a
a = b;// we now have two copies of b (+ discarded a copy of a)
b = tmp;// we now have two copies of tmp (+ discarded a copy of b)}
użycie move pozwala zamienić zasoby zamiast je kopiować:
template<class T>
swap(T& a, T& b){
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);}
Pomyśl o tym, co się stanie, gdy Tpowiedzmy vector<int>rozmiar n. W pierwszej wersji czytasz i zapisujesz 3 * n elementów, w drugiej wersji w zasadzie odczytujesz i zapisujesz tylko 3 wskaźniki do buforów wektorów oraz rozmiary 3 buforów. Oczywiście klasa Tmusi wiedzieć, jak się poruszać; twoja klasa powinna mieć operator przypisania ruchu i konstruktor ruchu, aby klasa Tdziałała.
Od dawna słyszałem o semantyce ruchów, nigdy nie zaglądałem w nie. Z podanego opisu wydaje się, że jest to płytka kopia zamiast głębokiej kopii.
Zebrafish
7
@TitoneMaurice: Tyle że nie jest to kopia - ponieważ pierwotna wartość nie jest już użyteczna.
einpoklum
3
@Zebrafish, nie możesz się bardziej mylić. Płytka kopia pozostawia oryginał w dokładnie tym samym stanie, ruch zwykle powoduje, że oryginał jest pusty lub znajduje się w innym ważnym stanie.
rubenvb 10.01.2018
16
@rubenvb Zebra nie jest całkowicie błędna. Chociaż prawdą jest, że oryginalny kanabiliowany obiekt jest zwykle celowo sabotowany, aby uniknąć mylących błędów (np. Ustawić jego wskaźniki na nullptr, aby zasygnalizować, że nie jest już posiadaczem pointee), faktem jest, że cały ruch jest wykonywany po prostu przez skopiowanie wskaźnika ze źródła do miejsca docelowego (i celowe unikanie robienia czegokolwiek z osobą wskazującą) w rzeczywistości przypomina płytką kopię. W rzeczywistości posunąłbym się do stwierdzenia, że ruch jest płytką kopią, po której opcjonalnie następuje częściowe samozniszczenie źródła. (cd.)
Wyścigi lekkości na orbicie
3
(cd.) Jeśli pozwolimy na tę definicję (a raczej ją lubię), to obserwacja @ Zebrafisha nie jest błędna, tylko nieco niekompletna.
Wyścigi lekkości na orbicie
145
Możesz użyć move, gdy potrzebujesz „przenieść” zawartość obiektu w inne miejsce, bez robienia kopii (tzn. Treść nie jest powielana, dlatego może być używana na niektórych obiektach, których nie można skopiować, np. Unikatowa_ptr). Możliwe jest również, że obiekt pobierze zawartość obiektu tymczasowego bez robienia kopii (i oszczędza dużo czasu), przy pomocy std :: move.
Przepraszam, jeśli moja odpowiedź przychodzi za późno, ale szukałem również dobrego linku do std :: move, i znalazłem linki powyżej nieco „surowe”.
To kładzie nacisk na odniesienie do wartości r, w którym kontekście powinieneś ich użyć, i myślę, że jest bardziej szczegółowe, dlatego chciałem udostępnić ten link tutaj.
Niezły link. Zawsze znajdowałem artykuł na Wikipedii i inne linki, na które natknąłem się dość myląco, ponieważ po prostu rzucają fakty na ciebie, pozostawiając ci ustalenie, jakie jest rzeczywiste znaczenie / uzasadnienie. Podczas gdy „semantyka przenoszenia” w konstruktorze jest dość oczywista, wszystkie te szczegóły dotyczące przekazywania && - wartości wokół nie są ... więc opis w stylu samouczka był bardzo miły.
Christian Stieber,
66
P: Co to jest std::move ?
ZA: std::move() jest funkcją z biblioteki standardowej C ++ do rzutowania na odwołanie do wartości.
Uproszczony std::move(t)jest równoważny z:
static_cast<T&&>(t);
Wartość jest wartością tymczasową, która nie utrzymuje się poza wyrażeniem, które ją definiuje, takim jak wynik funkcji pośredniej, który nigdy nie jest przechowywany w zmiennej.
int a =3;// 3 is a rvalue, does not exist after expression is evaluatedint b = a;// a is a lvalue, keeps existing after expression is evaluated
Jak widać, std::movezwraca T&&bez względu na to, czy zostanie wywołana z wartością ( T), typem referencji ( T&) czy wartością referencyjną wartości ( T&&).
P: Co to robi?
Odp .: Jako obsada nic nie robi podczas działania. Ważne jest tylko w czasie kompilacji, aby poinformować kompilator, że chcesz nadal traktować referencję jako wartość.
foo(3*5);// obviously, you are calling foo with a temporary (rvalue)int a =3*5;
foo(a);// how to tell the compiler to treat `a` as an rvalue?
foo(std::move(a));// will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)`
Czego nie robi:
Zrób kopię argumentu
Wywołaj konstruktor kopiowania
Zmień obiekt argumentu
P: Kiedy należy go używać?
Odp .: Powinieneś użyć, std::movejeśli chcesz wywoływać funkcje obsługujące semantykę przenoszenia z argumentem, który nie jest wartością (wyrażenie tymczasowe).
To rodzi dla mnie następujące pytania uzupełniające:
Co to jest semantyka ruchu? Semantyka przenoszenia w przeciwieństwie do semantyki kopiowania jest techniką programowania, w której elementy obiektu są inicjowane przez „przejęcie” zamiast kopiowania elementów innego obiektu. Takie „przejmowanie” ma sens tylko w przypadku wskaźników i uchwytów zasobów, które można tanio przenosić, kopiując uchwyt wskaźnika lub liczby całkowitej zamiast bazowych danych.
Jakie klasy i obiekty obsługują semantykę ruchów? Od programisty należy wdrożenie semantyki przenoszenia we własnych klasach, jeśli skorzystałoby z przeniesienia członków zamiast ich kopiowania. Po zaimplementowaniu semantyki przenoszenia bezpośrednio skorzystasz z pracy wielu programistów bibliotek, którzy dodali obsługę efektywnego zarządzania klasami z semantyką przenoszenia.
Dlaczego kompilator nie może tego sam zrozumieć? Kompilator nie może po prostu wywołać kolejnego przeciążenia funkcji, chyba że tak powiesz. Musisz pomóc kompilatorowi wybrać, czy ma być wywoływana wersja zwykła czy przeniesiona funkcji.
W jakich sytuacjach chciałbym powiedzieć kompilatorowi, że powinien traktować zmienną jak wartość? Najprawdopodobniej stanie się to w funkcjach szablonów lub bibliotek, gdzie wiesz, że można uzyskać wynik pośredni.
Duża +1 dla przykładów kodu z semantyką w komentarzach. Pozostałe najważniejsze odpowiedzi definiują std :: move za pomocą samego „move” - tak naprawdę nic nie wyjaśnia! --- Uważam, że warto wspomnieć, że nie zrobienie kopii argumentu oznacza, że pierwotnej wartości nie można wiarygodnie wykorzystać.
ty
34
sam std :: move nie robi wiele. Myślałem, że wywołuje on konstruktor ruchu dla obiektu, ale tak naprawdę wykonuje rzut typu (rzutowanie zmiennej lvalue na wartość, aby wymieniona zmienna mogła zostać przekazana jako argument do konstruktora ruchu lub operatora przypisania).
Zatem std :: move jest po prostu używany jako prekursor do użycia semantyki move. Semantyka przesuwania jest zasadniczo skutecznym sposobem radzenia sobie z obiektami tymczasowymi.
Rozważ obiekt A = B + C + D + E + F;
To ładnie wyglądający kod, ale E + F tworzy obiekt tymczasowy. Następnie D + temp tworzy kolejny obiekt tymczasowy i tak dalej. W każdym normalnym operatorze „+” klasy występują głębokie kopie.
Na przykład
ObjectObject::operator+(constObject& rhs){Object temp (*this);// logic for addingreturn temp;}
Utworzenie obiektu tymczasowego w tej funkcji jest bezużyteczne - te obiekty tymczasowe zostaną usunięte na końcu linii, gdy wyjdą poza zakres.
Możemy raczej użyć semantyki ruchu, aby „splądrować” obiekty tymczasowe i zrobić coś podobnego
Object&Object::operator+(Object&& rhs){// logic to modify rhs directlyreturn rhs;}
Pozwala to uniknąć niepotrzebnych głębokich kopii. W odniesieniu do przykładu jedyną częścią, w której zachodzi głębokie kopiowanie, jest teraz E + F. Reszta używa semantyki przenoszenia. Konstruktor ruchu lub operator przypisania również musi zostać zaimplementowany, aby przypisać wynik do A.
mówiłeś o semantyce ruchów. powinieneś dodać do swojej odpowiedzi, jak można używać std :: move, ponieważ pytanie o to pyta.
Koushik Shetty
2
@Koushik std :: move nie robi wiele - ale służy do implementacji semantyki move. Jeśli nie wiesz o std :: move, prawdopodobnie nie znasz też semantyki move
user929404
1
„nie robi wiele” (tak, tylko static_cast do odwołania do wartości). to, co faktycznie robi i robi to, o co poprosił PO. nie musisz wiedzieć, jak działa std :: move, ale wiesz, co robi semantyka move. ponadto, „ale jest stosowany do implementacji semantyki ruchu”, jest odwrotnie. znasz semantykę ruchu, a zrozumiesz std :: move inaczej nie. ruch tylko pomaga w ruchu i sam używa semantyki ruchu. std :: move robi tylko konwersję argumentu na odwołanie do wartości, czego wymaga semantyka przenoszenia.
Koushik Shetty
10
„ale E + F tworzy obiekt tymczasowy” - Operator +przesuwa się od lewej do prawej, a nie od prawej do lewej. Stąd B+Cbyłby pierwszy!
Ajay,
8
"Co to jest?" i „Co to robi?”zostało wyjaśnione powyżej.
Podam przykład „kiedy należy go użyć”.
Na przykład mamy klasę z dużą ilością zasobów, takich jak duża tablica.
classResHeavy{// ResHeavy means heavy resourcepublic:ResHeavy(int len=10):_upInt(newint[len]),_len(len){
cout<<"default ctor"<<endl;}ResHeavy(constResHeavy& rhs):_upInt(newint[rhs._len]),_len(rhs._len){
cout<<"copy ctor"<<endl;}ResHeavy&operator=(constResHeavy& rhs){
_upInt.reset(newint[rhs._len]);
_len = rhs._len;
cout<<"operator= ctor"<<endl;}ResHeavy(ResHeavy&& rhs){
_upInt = std::move(rhs._upInt);
_len = rhs._len;
rhs._len =0;
cout<<"move ctor"<<endl;}// check array validbool is_up_valid(){return _upInt !=nullptr;}private:
std::unique_ptr<int[]> _upInt;// heavy array resourceint _len;// length of int array};
Kod testowy:
void test_std_move2(){ResHeavy rh;// only one int[]// operator rh// after some operator of rh, it becomes no-use// transform it to other objectResHeavy rh2 = std::move(rh);// rh becomes invalid// show rh, rh2 it validif(rh.is_up_valid())
cout<<"rh valid"<<endl;else
cout<<"rh invalid"<<endl;if(rh2.is_up_valid())
cout<<"rh2 valid"<<endl;else
cout<<"rh2 invalid"<<endl;// new ResHeavy object, created by copy ctorResHeavy rh3(rh2);// two copy of int[]if(rh3.is_up_valid())
cout<<"rh3 valid"<<endl;else
cout<<"rh3 invalid"<<endl;}
Możemy to zobaczyć za std::movepomocąmove constructor marki przekształcić zasób łatwo.
Gdzie jeszcze jest std::move przydaje?
std::movemoże być również przydatny podczas sortowania tablicy elementów. Wiele algorytmów sortowania (takich jak sortowanie selekcyjne i bąbelkowe) działa poprzez zamianę par elementów. Wcześniej musieliśmy używać semantyki kopiowania, aby wykonać wymianę. Teraz możemy użyć semantyki ruchu, która jest bardziej wydajna.
Może być również przydatny, jeśli chcemy przenieść zawartość zarządzaną przez jeden inteligentny wskaźnik do drugiego.
std::move(T && t)
; istnieje równieżstd::move(InputIt first, InputIt last, OutputIt d_first)
algorytm związany zstd::copy
. Zwracam na to uwagę, aby inni nie byli tak zdezorientowani jak ja, kiedy po raz pierwszy skonfrontowałem się zstd::move
przyjęciem trzech argumentów. en.cppreference.com/w/cpp/algorithm/moveOdpowiedzi:
Strona Wikipedii na temat C ++ 11 Odnośniki do wartości R i konstruktory ruchów
(Oprócz operatorów kopiowania przypisania mają także operatory przypisania przeniesienia).
Type &&
).std::move()
jest rzutowaniem, które generuje odwołanie do wartości do obiektu, aby umożliwić poruszanie się z niego.Jest to nowy sposób C ++ pozwalający uniknąć kopii. Na przykład, używając konstruktora przenoszenia, a
std::vector
może po prostu skopiować swój wewnętrzny wskaźnik do danych do nowego obiektu, pozostawiając przeniesiony obiekt w stanie przeniesionym ze stanu, a zatem nie kopiując wszystkich danych. To byłoby C ++ - poprawne.Spróbuj googlingu, aby uzyskać semantykę ruchu, wartość rue, doskonałe przekazywanie.
źródło
std::move()
nie jest sposobem używania semantyki ruchów, semantyka ruchów jest wykonywana dla programisty w sposób transparentny.move
jest to tylko rzutowanie, które przekazuje wartość z jednego punktu do drugiego, gdzie oryginalna wartość nie będzie już używana.std::move
samo w sobie „nic” - ma zerowe skutki uboczne. To tylko sygnalizuje kompilatorowi, że programista nie dba już o to, co stanie się z tym obiektem. tzn. zezwala innym częściom oprogramowania na przemieszczanie się z obiektu, ale nie wymaga przenoszenia. W rzeczywistości odbiorca odwołania do wartości nie musi składać żadnych obietnic dotyczących tego, co zrobi lub nie zrobi z danymi.1. „Co to jest?”
Chociaż
std::move()
technicznie jest to funkcja - powiedziałbym, że tak naprawdę nie jest funkcją . Jest to rodzaj konwertera między sposobami, w których kompilator uwzględnia wartość wyrażenia.2. „Co to robi?”
Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że
std::move()
tak naprawdę nic nie rusza . Konwertuje wyrażenie od bycia lwartość (takich jak zmiennej o nazwie) do bycia xvalue . Wartość x mówi kompilatorowi:innymi słowy, kiedy używasz
std::move(x)
, pozwalasz kompilatorowi na kanibalizacjęx
. Zatem jeślix
, powiedzmy, ma własny bufor w pamięci - postd::move()
kompilacji może zamiast niego posiadać inny obiekt.Możesz także przejść z prvalue (np. Tymczasowego mijania), ale jest to rzadko przydatne.
3. „Kiedy należy go użyć?”
Innym sposobem na zadanie tego pytania jest: „Po co miałbym kanibalizować zasoby istniejącego obiektu?” cóż, jeśli piszesz kod aplikacji, prawdopodobnie nie będziesz się zbytnio bawić w tymczasowe obiekty tworzone przez kompilator. Zasadniczo robiłbyś to w miejscach takich jak konstruktory, metody operatora, funkcje podobne do algorytmów biblioteki standardowej itp., W których obiekty są często tworzone i niszczone automatycznie. Oczywiście to tylko ogólna zasada.
Typowym zastosowaniem jest „przenoszenie” zasobów z jednego obiektu do drugiego zamiast kopiowania. @Guillaume prowadzi do tej strony, która ma prosty krótki przykład: zamiana dwóch obiektów przy mniejszym kopiowaniu.
użycie move pozwala zamienić zasoby zamiast je kopiować:
Pomyśl o tym, co się stanie, gdy
T
powiedzmyvector<int>
rozmiar n. W pierwszej wersji czytasz i zapisujesz 3 * n elementów, w drugiej wersji w zasadzie odczytujesz i zapisujesz tylko 3 wskaźniki do buforów wektorów oraz rozmiary 3 buforów. Oczywiście klasaT
musi wiedzieć, jak się poruszać; twoja klasa powinna mieć operator przypisania ruchu i konstruktor ruchu, aby klasaT
działała.źródło
Możesz użyć move, gdy potrzebujesz „przenieść” zawartość obiektu w inne miejsce, bez robienia kopii (tzn. Treść nie jest powielana, dlatego może być używana na niektórych obiektach, których nie można skopiować, np. Unikatowa_ptr). Możliwe jest również, że obiekt pobierze zawartość obiektu tymczasowego bez robienia kopii (i oszczędza dużo czasu), przy pomocy std :: move.
Ten link naprawdę mi pomógł:
http://thbecker.net/articles/rvalue_references/section_01.html
Przepraszam, jeśli moja odpowiedź przychodzi za późno, ale szukałem również dobrego linku do std :: move, i znalazłem linki powyżej nieco „surowe”.
To kładzie nacisk na odniesienie do wartości r, w którym kontekście powinieneś ich użyć, i myślę, że jest bardziej szczegółowe, dlatego chciałem udostępnić ten link tutaj.
źródło
P: Co to jest
std::move
?ZA:
std::move()
jest funkcją z biblioteki standardowej C ++ do rzutowania na odwołanie do wartości.Uproszczony
std::move(t)
jest równoważny z:Wartość jest wartością tymczasową, która nie utrzymuje się poza wyrażeniem, które ją definiuje, takim jak wynik funkcji pośredniej, który nigdy nie jest przechowywany w zmiennej.
Implementacja std :: move () jest podana w N2027: „Krótkie wprowadzenie do odwołań do wartości” w następujący sposób:
Jak widać,
std::move
zwracaT&&
bez względu na to, czy zostanie wywołana z wartością (T
), typem referencji (T&
) czy wartością referencyjną wartości (T&&
).P: Co to robi?
Odp .: Jako obsada nic nie robi podczas działania. Ważne jest tylko w czasie kompilacji, aby poinformować kompilator, że chcesz nadal traktować referencję jako wartość.
Czego nie robi:
P: Kiedy należy go używać?
Odp .: Powinieneś użyć,
std::move
jeśli chcesz wywoływać funkcje obsługujące semantykę przenoszenia z argumentem, który nie jest wartością (wyrażenie tymczasowe).To rodzi dla mnie następujące pytania uzupełniające:
Co to jest semantyka ruchu? Semantyka przenoszenia w przeciwieństwie do semantyki kopiowania jest techniką programowania, w której elementy obiektu są inicjowane przez „przejęcie” zamiast kopiowania elementów innego obiektu. Takie „przejmowanie” ma sens tylko w przypadku wskaźników i uchwytów zasobów, które można tanio przenosić, kopiując uchwyt wskaźnika lub liczby całkowitej zamiast bazowych danych.
Jakie klasy i obiekty obsługują semantykę ruchów? Od programisty należy wdrożenie semantyki przenoszenia we własnych klasach, jeśli skorzystałoby z przeniesienia członków zamiast ich kopiowania. Po zaimplementowaniu semantyki przenoszenia bezpośrednio skorzystasz z pracy wielu programistów bibliotek, którzy dodali obsługę efektywnego zarządzania klasami z semantyką przenoszenia.
Dlaczego kompilator nie może tego sam zrozumieć? Kompilator nie może po prostu wywołać kolejnego przeciążenia funkcji, chyba że tak powiesz. Musisz pomóc kompilatorowi wybrać, czy ma być wywoływana wersja zwykła czy przeniesiona funkcji.
W jakich sytuacjach chciałbym powiedzieć kompilatorowi, że powinien traktować zmienną jak wartość? Najprawdopodobniej stanie się to w funkcjach szablonów lub bibliotek, gdzie wiesz, że można uzyskać wynik pośredni.
źródło
sam std :: move nie robi wiele. Myślałem, że wywołuje on konstruktor ruchu dla obiektu, ale tak naprawdę wykonuje rzut typu (rzutowanie zmiennej lvalue na wartość, aby wymieniona zmienna mogła zostać przekazana jako argument do konstruktora ruchu lub operatora przypisania).
Zatem std :: move jest po prostu używany jako prekursor do użycia semantyki move. Semantyka przesuwania jest zasadniczo skutecznym sposobem radzenia sobie z obiektami tymczasowymi.
Rozważ obiekt
A = B + C + D + E + F;
To ładnie wyglądający kod, ale E + F tworzy obiekt tymczasowy. Następnie D + temp tworzy kolejny obiekt tymczasowy i tak dalej. W każdym normalnym operatorze „+” klasy występują głębokie kopie.
Na przykład
Utworzenie obiektu tymczasowego w tej funkcji jest bezużyteczne - te obiekty tymczasowe zostaną usunięte na końcu linii, gdy wyjdą poza zakres.
Możemy raczej użyć semantyki ruchu, aby „splądrować” obiekty tymczasowe i zrobić coś podobnego
Pozwala to uniknąć niepotrzebnych głębokich kopii. W odniesieniu do przykładu jedyną częścią, w której zachodzi głębokie kopiowanie, jest teraz E + F. Reszta używa semantyki przenoszenia. Konstruktor ruchu lub operator przypisania również musi zostać zaimplementowany, aby przypisać wynik do A.
źródło
+
przesuwa się od lewej do prawej, a nie od prawej do lewej. StądB+C
byłby pierwszy!"Co to jest?" i „Co to robi?”zostało wyjaśnione powyżej.
Podam przykład „kiedy należy go użyć”.
Na przykład mamy klasę z dużą ilością zasobów, takich jak duża tablica.
Kod testowy:
wyjście jak poniżej:
Możemy to zobaczyć za
std::move
pomocąmove constructor
marki przekształcić zasób łatwo.Gdzie jeszcze jest
std::move
przydaje?std::move
może być również przydatny podczas sortowania tablicy elementów. Wiele algorytmów sortowania (takich jak sortowanie selekcyjne i bąbelkowe) działa poprzez zamianę par elementów. Wcześniej musieliśmy używać semantyki kopiowania, aby wykonać wymianę. Teraz możemy użyć semantyki ruchu, która jest bardziej wydajna.Może być również przydatny, jeśli chcemy przenieść zawartość zarządzaną przez jeden inteligentny wskaźnik do drugiego.
Cytowane:
źródło
Oto pełny przykład użycia std :: move dla (prostego) niestandardowego wektora
Oczekiwany wynik:
Kompiluj jako:
Kod:
źródło