2012-07-20 18 views
17

Załóżmy, że mam następujący kod:Move z wektorem :: push_back

#include <vector> 
struct A { 
    int a; 
    int x; 
}; 
int main() { 
    using namespace std; 
    A a1; 
    A a2; 
    vector<A> va; 
    va.push_back(a1); 
    va.push_back(move(a2)); 
} 

Zdaję sobie sprawę, że elementy z std :: vector są przechowywane w sposób zwarty, w przeciwieństwie do std :: listy. W powyższym kodzie został przeniesiony kod a2, ale czy naprawdę nie ma kopiowania a2 do wektora va? Jaka jest różnica między va.push_back(a2); i ?

+2

W twoim przypadku 'std :: move'ing' a2' robi dokładnie * nic *, ponieważ jest to typ płaski (tzn. Nie ma danych zewnętrznych) i nadal po prostu kopiuje. – Xeo

+0

@cdhowie Dzięki. poprawione. – ggg

+0

Możesz przeczytać [Czy ktoś może mi wyjaśnić semantykę przeniesienia?] (Http://stackoverflow.com/questions/3106110/) dla wprowadzenia do poruszania semantyki. – fredoverflow

Odpowiedz

26

W twoim przypadku nie ma skutecznej różnicy, ponieważ używasz konstruktorów kopiowania dostarczonych przez kompilator. Zauważysz zauważalną różnicę w wydajności, gdy używasz obiektów, które są ruchome i wymagasz dużo wysiłku, aby je skopiować. W takim przypadku użycie push_back(x) utworzyłoby kopię obiektu, podczas gdy push_back(move(x)) powiedziałoby push_back(), że może "ukraść" zawartość x, pozostawiając x w stanie niezdatnym do użytku i niezdefiniowanym.

Zastanów się, czy masz wektor list (std::vector<std::list<int> >) i chcesz wypchnąć listę zawierającą 100 000 elementów. Bez numeru move() zostanie skopiowana cała struktura listy i wszystkie 100 000 elementów. W przypadku move() niektóre wskaźniki i inne małe fragmenty danych są pomieszane, i to wszystko. To będzie dużo szybciej i będzie wymagało mniejszego całkowitego zużycia pamięci.

+1

Dlaczego? move c-tor zostanie wygenerowany automatycznie, nie tak? – ForEveR

+6

@ForEveR Nie ma znaczenia, czy jeden jest generowany automatycznie, czy nie, ponieważ nie ma żadnych przydziałów w strukturze "A", którą można przenieść. Masz tylko dwa 'int's, a konstruktor ruchu zrobi to samo, co zrobi konstruktor kopiowania: przypisz wartości przechowywane w intach na obiekcie źródłowym do nowego obiektu. Nie ma możliwości optymalizacji w scenariuszu przenoszenia z tym typem, ponieważ jest on już tak optymalny, jak tylko może uzyskać. – cdhowie

+0

@cdhowie Więc coś będzie zawsze kopiowane podczas ruchu? – ggg

14

Podczas korzystania va.push_back(a2) wersję vector<T>::push_back(const T&) zostanie wywołana, gdy używasz va.push_back(move(a2)) wersja vector<T>::push_back(T&&) zostanie wywołana ...

Ale w twoim przypadku nie ma różnicy dla perfomance, ponieważ

15 niejawnie zdefiniowany konstruktor kopiowania/przenoszenia dla niezłącznej klasy X wykonuje proporcjonalne kopiowanie/przenoszenie swoich baz i elementów.

Paragraf 12.8 szkic n3337.

0

Chcę zauważyć coś, czego inne odpowiedzi nie przeszły; jest to, że ?.push_back(move(?)) będzie wolniejszy niż ?.push_back(?) w twoim przypadku (gdy masz obiekty do kopiowania trywialnego), ponieważ konstruktor ruchu musi zerować \ ustawić obiekt, który skutecznie pisze \ kopiowanie dwóch obiektów.

+0

Konstruktor ruchów nie musi wykonywać żadnych czynności względem poruszanego obiektu. Nie trzeba niczego zerować, chyba że przeniesione wskaźniki muszą zostać zresetowane do wartości null. (Konstruktorzy generowania ruchów generowane przez kompilatory nie zamierzają zerwać obiektu źródłowego.) – cdhowie