2016-02-15 24 views
11

Czy jest jakaś korzyść z jednoczesnego używania std::vector::emplace_back i std::move? lub jest to po prostu zbędne, ponieważ std::vector::emplace_back wykona in situ-construction?std :: wektor :: emplace_back i std :: move

Obudowy dla wyjaśnienia:

std::vector<std::string> bar; 

pierwsze:

bar.emplace_back(std::move(std::string("some_string"))); 

drugie:

std::string str("some_string"); 
bar.emplace_back(std::move(str)); 

trzecie:

bar.emplace_back(std::move("some_string")); 
+1

Trzeci ruch, przynajmniej, jest bez sensu. Ten łańcuch literowy jest const, więc nie można go przenieść. –

Odpowiedz

13

W drugiej wersji istnieje przewaga. Wywołanie emplace_back wywoła konstruktor ruchu std::string przy użyciu std::move, który można zapisać na kopii (o ile ten ciąg nie jest przechowywany w buforze SSO). Zauważ, że jest to w zasadzie takie samo, jak push_back w tym przypadku.

std::move w pierwszej wersji jest niepotrzebna, ponieważ ciąg jest już wartością prava.

std::move w trzeciej wersji nie ma znaczenia, ponieważ literał ciągu nie może być przeniesiony z.

Najprostsza i najskuteczniejsza metoda jest taka:

bar.emplace_back("some_string"); 

To nie wymaga żadnych zbędnych std::string konstrukcje jako dosłowne jest doskonały-przekazany do konstruktora.

+0

Czy mógłbyś w tym przypadku wyjaśnić "tak samo jak" push_back' "? W takim razie dokładnie? Czy 'emplace_back' zawsze można zastąpić' push_back', jeśli jego argumentem jest 'move'd? –

1

Jest to punkt widzenia w drugim przypadku. Rozważmy następujący kod:

int main() 
{ 
    std::vector<std::string> bar; 
    std::string str("some_string"); 
    bar.emplace_back(std::move(str)); 
    // bar.emplace_back(str); 
    std::cout << str << std::endl; 
} 

Jeżeli powyższy zmienić komentarz do linii, można zobaczyć, że skończy się z dwiema kopiami „some_string” (jeden w bar i jeden w str). Więc coś zmienia.

W przeciwnym razie pierwszy przesuwa tymczasowy, a trzeci przesuwa ciągły tekst literowy. Nie robi nic.

2

Cała idea emplace_back polega na pozbyciu się operacji kopiowania i przenoszenia. Musisz tylko przekazać parametry wejściowe std::string do emplace_back. Obiekt std::string zostanie skonstruowany w ramach metody emplace_back.

bar.emplace_back("some_string"); 

Jeśli masz już ciąg znaków, warto użyć std::move. Obiekt std::string zostanie skonstruowany wewnątrz emplace_back przez przeniesienie danych z str.

std::string str("some_string"); 
bar.emplace_back(std::move(str)); 
4

emplace_back wzywa do somehthing jak

new (data+size) T(std::forward<Args>(args)...); 

jeśli args są proste - nie - RValue-odwoływać std::string wyrażenie zostanie skompilowany do

new (data+size) std::string(str); //str is lvalue - calls std::string::string(const string& rhs) 

czyli konstruktor kopiujący odbędzie miejsce. ale jeśli używasz std::move na str, kod zostanie skompilowany do

new (data+size) std::string(str); //str is r-value reference, calls std::string::string(string&& rhs) 

więc przenieść semantykę ma miejsce. to jest ogromny wzrost wydajności.
zwróć uwagę, że str to l-wartość, ma nazwę, więc aby utworzyć z niej wartość-odniesienia, musisz użyć std::move.

w przykładzie

vec.emplace_back("some literal"); 

kod zostanie skompilowany do

new (data+size) std::string("literal"); //calls std::string::string(const char*); 

więc nie tymczasowych.

trzeci przykład to nonsens. nie możesz przenosić literałów.

Powiązane problemy