Co to jest STD:: move () i kiedy powinno być używane?

    Co to jest? Co to robi?
  1. Kiedy należy go stosować?

Dobre linki są doceniane.

Author: einpoklum, 2010-08-05

6 answers

Http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics

  1. W C++11, oprócz konstruktorów kopiujących, obiekty mogą mieć konstruktory ruchome.
    (Oprócz operatorów przydziałów kopiowania, mają operatory przydziałów przenoszenia.)
  2. konstruktor move jest używany zamiast konstruktora kopiującego, jeśli obiekt ma typ " rvalue-reference" (Type &&).
  3. std::move() jest odlewem, który tworzy rvalue-odniesienie do obiektu, aby umożliwić przejście z niego.

To nowy sposób na unikanie kopii w C++. Na przykład, używając konstruktora move, std::vector może po prostu skopiować swój wewnętrzny wskaźnik do danych do nowego obiektu, pozostawiając przeniesiony obiekt w nieprawidłowym stanie, unikając kopiowania wszystkich danych. To byłoby C++-valid.

Spróbuj wyszukać w Google semantykę ruchu, rvalue, perfect forwarding.

 191
Author: Scharron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-19 22:53:45

Move można użyć, gdy trzeba" przenieść " zawartość obiektu w inne miejsce, bez wykonywania kopii (np. zawartość nie jest duplikowana, dlatego może być używana na niektórych niekopiowalnych obiektach, takich jak unique_ptr). Jest również możliwe, aby obiekt pobierał zawartość obiektu tymczasowego bez wykonywania kopii (i oszczędzał dużo czasu), za pomocą 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 też dobrego linku do std:: move, a linki powyżej znalazłem trochę "surowo".

To kładzie nacisk na odniesienie do wartości r, w jakim kontekście należy ich używać, i myślę, że jest bardziej szczegółowy, dlatego chciałem podzielić się tym linkiem tutaj.

 121
Author: Guillaume,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-22 06:26:53

1. "Co to jest?"

Podczas gdy std::move() jest technicznie funkcją-powiedziałbym to nie jest tak naprawdę funkcją. Jest to rodzaj konwertera pomiędzy sposobami, w jakie kompilator rozważa wartość wyrażenia.

2. "Co to robi?"

Pierwszą rzeczą, którą należy zauważyć, jest to, że std::move() nie porusza niczego .

jeśli kiedykolwiek oglądałeś serial animowany Bleach - to odpowiednik Quincy Seele Schneider'S Reishi zmiękczanie.

Poważnie, konwertuje wyrażenie z lvalue lub pure rvalue (takie jak zmienna, której możesz używać przez długi czas, lub tymczasowa, którą przekazujesz przez jakiś czas) do xvalue. Xvalue mówi kompilatorowi:

Możesz mnie splądrować, przenieść wszystko, co trzymam i użyć go gdzie indziej (ponieważ wkrótce będę zniszczony anyway)".

Innymi słowy, kiedy używasz std::move(x), pozwalasz kompilatorowi kanibalizować x. Tak więc jeśli x ma, powiedzmy, własny bufor w pamięci - po std::move()ING kompilator może mieć inny obiekt, który jest jego właścicielem.

3. "Kiedy należy go używać?"

Innym sposobem zadawania tego pytania jest "do czego mógłbym użyć / kanibalizować zasoby obiektu?"cóż, jeśli piszesz kod aplikacji, prawdopodobnie nie będziesz za bardzo grzebał w obiektach tymczasowych stworzony przez kompilator. Więc głównie robisz to w miejscach takich jak konstruktory, metody operatorów, funkcje podobne do algorytmu stl itp. gdzie obiekty są tworzone i niszczone automagicznie dużo. Oczywiście, to tylko zasada.

Typowym zastosowaniem jest "przenoszenie" zasobów z jednego obiektu do drugiego zamiast kopiowania. @Guillaume odsyła do tej strony , która ma prosty krótki przykład: Zamiana dwóch obiektów z mniejszą ilością kopiowania.

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 na aby zamienić zasoby zamiast kopiować je wokół:

template <class T>
swap(T& a, T& b) {
    T tmp(std::move(a));
    a = std::move(b);   
    b = std::move(tmp);
}

Pomyśl, co się dzieje, gdy T jest, powiedzmy, vector<int> wielkości N. w pierwszej wersji czytasz i zapisujesz 3 * N elementów, w drugiej w zasadzie czytasz i zapisujesz tylko 3 wskaźniki do buforów wektorów. Oczywiście, Klasa T musi wiedzieć, jak wykonać ruch; powinieneś mieć operator przypisania ruchu i konstruktor ruchu dla klasy T, aby to zadziałało.

 99
Author: einpoklum,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-05 12:15:49

P: Co to jest std::move?

A: std::move() jest funkcją z biblioteki standardowej C++ do przesyłania do referencji rvalue.

W uproszczeniu std::move(t) jest równoważne:

static_cast<T&&>(t);

Rvalue jest wartością tymczasową, która nie jest utrzymywana poza wyrażeniem, które ją definiuje, np. pośredni wynik funkcji, który nigdy nie jest przechowywany w zmiennej.

int a = 3; // 3 is a rvalue, does not exist after expression is evaluated
int b = a; // a is a lvalue, keeps existing after expression is evaluated

Implementacja std:: move() jest podana w N2027: "Krótkie wprowadzenie do referencji Rvalue" jako następuje:

template <class T>
typename remove_reference<T>::type&&
std::move(T&& a)
{
    return a;
}

Jak widzisz, std::move zwraca T&& bez względu na to, czy jest wywołane z wartością (T), typem referencyjnym (T&) czy referencją rvalue (T&&).

P: Co to robi?

A: jako obsada, nie robi nic podczas wykonywania. W czasie kompilacji istotne jest tylko poinformowanie kompilatora, że chcesz kontynuować rozpatrywanie referencji jako wartości R.

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)`

Co robi a nie robić:

  • zrób kopię argument
  • wywołanie konstruktora kopii
  • Zmień obiekt argumentu

P: Kiedy należy go używać?

A: powinieneś użyć std::move Jeśli chcesz wywołać funkcje obsługujące semantykę move z argumentem, który nie jest wartością rvalue (wyrażenie tymczasowe).

Nasuwa mi się następujące pytania:

  • Czym jest semantyka ruchu? Semantyka przenoszenia w przeciwieństwie do semantyki kopiowania jest techniką programowania, w której elementy składowe obiektu są inicjowane przez "przejęcie" zamiast kopiowania elementów składowych innego obiektu. Takie "przejęcie" ma sens tylko w przypadku wskaźników i uchwytów zasobów, które można tanio przenieść poprzez skopiowanie uchwytu wskaźnika lub liczby całkowitej, a nie bazowych danych.

  • Jakie klasy i Obiekty wspierają semantykę move? To do Ciebie, jako programisty, należy implementacja semantyki move w Twoich klasach, jeśli zamiast tego skorzystają na przeniesieniu swoich członków kopiowania ich. Po zaimplementowaniu semantyki move, bezpośrednio skorzystasz z pracy wielu programistów bibliotek, którzy dodali obsługę klas z semantyką move.

  • Dlaczego kompilator nie może sam tego rozgryźć? 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łana zwykła czy ruchowa wersja funkcji.

  • W jakich sytuacjach Chcę powiedzieć kompilatorowi, że powinien traktować zmienną jako wartość R? Będzie to najprawdopodobniej miało miejsce w funkcjach szablonu lub biblioteki, gdzie wiadomo, że można uratować pośredni wynik.

 27
Author: Christopher Oezbek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-27 21:02:16

Std:: move samo w sobie nie robi zbyt wiele. Myślałem, że wywołał konstruktor przesunięty dla obiektu, ale tak naprawdę po prostu wykonuje Typ cast (odlewanie zmiennej lvalue do wartości R, aby ta zmienna mogła być przekazana jako argument do konstruktora przesunięcia lub operatora przypisania).

Więc std:: move jest po prostu używany jako prekursor semantyki ruchu. Semantyka Move jest zasadniczo efektywnym sposobem radzenia sobie z obiektami tymczasowymi.

Rozważmy 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

Object Object::operator+ (const Object& rhs) {
    Object temp (*this);
    // logic for adding
    return temp;
}

Tworzenie tymczasowego obiektu w tej funkcji jest bezużyteczne - te tymczasowe obiekty zostaną usunięte na końcu linii, gdy wyjdą poza zakres.

Możemy raczej użyć semantyki move, aby "grabić" obiekty tymczasowe i robić coś jak

 Object& Object::operator+ (Object&& rhs) {
     // logic to modify rhs directly
     return rhs;
 }
To pozwala uniknąć niepotrzebnych głębokich kopii. W odniesieniu do przykładu, jedyną częścią, w której występuje Głębokie kopiowanie, jest teraz E + F. reszta wykorzystuje semantykę move. Aby przypisać wynik do A.
 26
Author: user929404,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-19 15:23:32

What is it? oraz What does it do? zostało wyjaśnione powyżej.

Podam przykład when it should be used.

Na przykład, mamy klasę z dużą ilością zasobów, takich jak big array w niej.

class ResHeavy{ //  ResHeavy means heavy resource
    public:
        ResHeavy(int len=10):_upInt(new int[len]),_len(len){
            cout<<"default ctor"<<endl;
        }

        ResHeavy(const ResHeavy& rhs):_upInt(new int[rhs._len]),_len(rhs._len){
            cout<<"copy ctor"<<endl;
        }

        ResHeavy& operator=(const ResHeavy& rhs){
            _upInt.reset(new int[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 valid
    bool is_up_valid(){
        return _upInt != nullptr;
    }

    private:
        std::unique_ptr<int[]> _upInt; // heavy array resource
        int _len; // length of int array
};

Kod testu:

void test_std_move2(){
    ResHeavy rh; // only one int[]
    // operator rh

    // after some operator of rh, it becomes no-use
    // transform it to other object
    ResHeavy rh2 = std::move(rh); // rh becomes invalid

    // show rh, rh2 it valid
    if(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 ctor
    ResHeavy rh3(rh2);  // two copy of int[]

    if(rh3.is_up_valid())
        cout<<"rh3 valid"<<endl;
    else
        cout<<"rh3 invalid"<<endl;
}

Wyjście jak poniżej:

default ctor
move ctor
rh invalid
rh2 valid
copy ctor
rh3 valid

Widzimy, że std::move z move constructor ułatwia transformację zasobu.

Gdzie jeszcze std:: move jest przydatne?

Std:: move może być również użyteczne podczas sortowania tablicy elementów. Wiele sortowania algorytmy (takie jak sortowanie selekcji i sortowanie bąbelkowe) działają poprzez zamianę par elementów. Wcześniej musieliśmy uciekać się do semantyki kopiowania, aby dokonać wymiany. Teraz możemy użyć semantyki move, która jest bardziej efektywna.

Może być również przydatny, jeśli chcemy przenieść zawartość zarządzaną przez jeden inteligentny wskaźnik do drugiego.

Cytat:

Https://www.learncpp.com/cpp-tutorial/15-4-stdmove/

 0
Author: Jayhello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-22 11:41:53