W C ++ 11 emplace_back()
jest ogólnie preferowane (pod względem wydajności), push_back()
ponieważ umożliwia konstruowanie w miejscu, ale czy nadal tak jest w przypadku używania push_back(std::move())
z już zbudowanym obiektem?
Na przykład, czy emplace_back()
nadal jest preferowany w takich przypadkach jak poniżej?
std::string mystring("hello world");
std::vector<std::string> myvector;
myvector.emplace_back(mystring);
myvector.push_back(std::move(mystring));
// (of course assuming we don't care about using the value of mystring after)
Dodatkowo, czy w powyższym przykładzie jest jakaś korzyść, aby zamiast tego zrobić:
myvector.emplace_back(std::move(mystring));
czy też ruch tutaj jest całkowicie zbędny, czy nie ma żadnego skutku?
c++11
move-semantics
push-back
emplace
Zamieszki
źródło
źródło
myvector.emplace_back(mystring);
kopiuje i nie porusza się. Pozostałe dwa ruchy i powinny być równoważne.Odpowiedzi:
Zobaczmy, jak działają różne podane przez Ciebie wywołania:
emplace_back(mystring)
: To jest konstrukcja lokalna nowego elementu z dowolnym podanym argumentem. Ponieważ podałeś lwartość, ta konstrukcja lokalna jest w rzeczywistości konstrukcją kopiującą, tj. Jest to to samo, co wywołaniepush_back(mystring)
push_back(std::move(mystring))
: To wywołuje metodę move-insertion, która w przypadku std :: string jest in-place move-construction.emplace_back(std::move(mystring))
: To jest ponownie konstrukcja lokalna z podanymi przez Ciebie argumentami. Ponieważ argument ten jest wartością r, wywołuje konstruktor ruchustd::string
, tj. Jest to konstrukcja ruchu w miejscu, taka jak w 2.Innymi słowy, jeśli wywołane z jednym argumentem typu T, czy to rvalue, czy lvalue,
emplace_back
ipush_back
są równoważne.Jednak dla każdego innego argumentu
emplace_back
wygrywa wyścig, na przykład zchar const*
avector<string>
:emplace_back("foo")
wzywastring::string(char const*)
do budowy na miejscu.push_back("foo")
najpierw musi wywołaćstring::string(char const*)
niejawną konwersję potrzebną do dopasowania podpisu funkcji, a następnie wstawienie ruchu, jak w przypadku 2. powyżej. Dlatego jest równoważnepush_back(string("foo"))
źródło
s
mogą być definiowane jako RValue odniesienia, które wiąże się tylko z rvalues, ale wewnątrzfoo
,s
jest lwartością.Emplace_back pobiera listę referencji rvalue i próbuje bezpośrednio skonstruować element kontenera. Możesz wywołać embrace_back ze wszystkimi typami obsługiwanymi przez konstruktory elementu kontenera. Kiedy wywołuje się embrace_back dla parametrów, które nie są referencjami rvalue, „powraca” do normalnych referencji i przynajmniej konstruktor kopiujący jest wywoływany, gdy parametr i elementy kontenera są tego samego typu. W twoim przypadku 'myvector.emplace_back (mystring)' powinien utworzyć kopię łańcucha, ponieważ kompilator nie mógł wiedzieć, że parametr myvector jest ruchomy. Więc wstaw std :: move, co daje pożądane korzyści. Push_back powinien działać tak samo dobrze jak embrace_back dla już skonstruowanych elementów.
źródło