push back vs emplace back
Jestem trochę zdezorientowany co do różnicy między push_back
i emplace_back
.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Ponieważ istnieje push_back
przeciążenie biorąc referencję rvalue nie bardzo rozumiem, jaki cel emplace_back
staje się?
6 answers
Oprócz tego, co gość powiedział:
Funkcja void emplace_back(Type&& _Val)
dostarczona przez MSCV10 jest niezgodna i zbędna, ponieważ, jak zauważyłeś, jest ściśle równoważna push_back(Type&& _Val)
.
Ale prawdziwa forma C++0x emplace_back
jest naprawdę przydatna: void emplace_back(Args&&...)
;
Zamiast value_type
pobiera zmienną listę argumentów, co oznacza, że możesz teraz doskonale przekazać argumenty i zbudować bezpośrednio obiekt do kontenera bez tymczasowego.
Jest to przydatne, ponieważ bez względu na to, ile sprytu RVO I move semantic wnoszą do tabeli, nadal istnieją skomplikowane przypadki, w których push_back może tworzyć niepotrzebne kopie (lub przenosić). Na przykład, z tradycyjną funkcją insert()
std::map
, musisz utworzyć tymczasową, która następnie zostanie skopiowana do std::pair<Key, Value>
, która następnie zostanie skopiowana do mapy:
std::map<int, Complicated> m;
int anInt = 4;
double aDouble = 5.0;
std::string aString = "C++";
// cross your finger so that the optimizer is really good
m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));
// should be easier for the optimizer
m.emplace(4, anInt, aDouble, aString);
Dlaczego więc nie zaimplementowali odpowiedniej wersji emplace_back w MSVC? Właściwie, to mnie wkurzyło. również jakiś czas temu, więc zadałem to samo pytanie na blogu Visual C++ . Oto odpowiedź Stephan T Lavavej, oficjalnego opiekuna implementacji biblioteki standardowej Visual C++ w Microsoft.
To zrozumiała decyzja. Każdy, kto choć raz próbował emulować różne szablony za pomocą preprocesora, wie, jak obrzydliwe staje się to.P: czy funkcje emplace w wersji beta 2 są teraz tylko jakimś zastępczym elementem?
Odp: Jak zapewne wiesz, różne szablony nie są zaimplementowane w VC10. My symuluj je za pomocą preprocesora Maszyny do takich rzeczy jak
make_shared<T>()
, tuple, i Nowy rzeczy w<functional>
. To maszyny preprocesorowe są stosunkowo trudne w użyciu i utrzymaniu. Również, znacząco wpływa na kompilację prędkość, jak musimy wielokrotnie dołącz do nagłówków. Ze względu na połączenie naszych ograniczeń czasowych i prędkości kompilacji, my nie symulowano zmiennych szablonów w naszych funkcjach emplace.Gdy zmienne szablony są zaimplementowane w kompilatorze, można spodziewaj się, że skorzystamy z ich w bibliotekach, m.in. w nasze stanowisko funkcjonuje. Bierzemy zgodność bardzo poważnie, ale niestety, nie możemy zrobić wszystkiego wszystko na raz.
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-06-26 21:30:17
emplace_back
nie powinien przyjmować argumentu typu vector::value_type
, lecz zmiennych argumentów, które są przekazywane do konstruktora dołączonego elementu.
template <class... Args> void emplace_back(Args&&... args);
Możliwe jest przekazanie value_type
, które zostanie przekazane do konstruktora kopiującego.
Ponieważ przekazuje argumenty, oznacza to, że jeśli nie masz wartości rvalue, to nadal oznacza, że kontener będzie przechowywał "skopiowaną" kopię, a nie przeniesioną kopię.
std::vector<std::string> vec;
vec.emplace_back(std::string("Hello")); // moves
std::string s;
vec.emplace_back(s); //copies
Ale powyższe powinno być identyczne z tym, co robi push_back
. On prawdopodobnie raczej przeznaczone do takich przypadków użycia jak:
std::vector<std::pair<std::string, std::string> > vec;
vec.emplace_back(std::string("Hello"), std::string("world"));
// should end up invoking this constructor:
//template<class U, class V> pair(U&& x, V&& y);
//without making any copies of the strings
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
2010-11-29 12:52:57
Optymalizację dla emplace_back
można zademonstrować w następnym przykładzie.
Dla emplace_back
konstruktor A (int x_arg)
zostanie wywołany. Oraz dla
push_back
A (int x_arg)
nazywa się pierwszy i move A (A &&rhs)
nazywa się później.
Oczywiście konstruktor musi być oznaczony jako explicit
, ale dla obecnego przykładu dobrze jest usunąć explicitness.
#include <iostream>
#include <vector>
class A
{
public:
A (int x_arg) : x (x_arg) { std::cout << "A (x_arg)\n"; }
A () { x = 0; std::cout << "A ()\n"; }
A (const A &rhs) noexcept { x = rhs.x; std::cout << "A (A &)\n"; }
A (A &&rhs) noexcept { x = rhs.x; std::cout << "A (A &&)\n"; }
private:
int x;
};
int main ()
{
{
std::vector<A> a;
std::cout << "call emplace_back:\n";
a.emplace_back (0);
}
{
std::vector<A> a;
std::cout << "call push_back:\n";
a.push_back (1);
}
return 0;
}
Wyjście:
call emplace_back:
A (x_arg)
call push_back:
A (x_arg)
A (A &&)
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-14 09:15:18
emplace_back
zgodna implementacja przekaże argumenty do konstruktora vector<Object>::value_type
po dodaniu do wektora. Przypominam sobie, że Visual Studio nie obsługiwało różnych szablonów, ale z różnymi szablonami będą obsługiwane w Visual Studio 2013 RC, więc domyślam się, że zostanie dodany zgodny podpis.
Z emplace_back
, jeśli przekazujesz argumenty bezpośrednio do konstruktora vector<Object>::value_type
, nie potrzebujesz typu, aby był ruchomy lub kopiowalny dla funkcji emplace_back
, ściśle mówiąc. W przypadku vector<NonCopyableNonMovableObject>
nie jest to przydatne, ponieważ vector<Object>::value_type
potrzebuje typu kopiowalnego lub ruchomego do wzrostu.
Ale zauważ , że może to być przydatne dla std::map<Key, NonCopyableNonMovableObject>
, ponieważ po przydzieleniu wpisu na mapie nie trzeba go już przenosić ani kopiować, w przeciwieństwie do vector
, co oznacza, że możesz efektywnie używać std::map
z odwzorowanym typem, który nie jest ani kopiowalny, ani ruchomy.
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-08-17 08:58:08
Jeszcze jeden w przypadku List:
/ / konstruuje elementy w miejscu.
emplace_back ("element");
/ / utworzy nowy obiekt, a następnie skopiuje (lub przeniesie) jego wartość argumentów. push_back (explicitDataType {"element"});
Ładny kod dla push_back i emplace_back jest pokazany tutaj.
Http://en.cppreference.com/w/cpp/container/vector/emplace_back
Możesz zobaczyć operację przenoszenia na push_back, a nie na emplace_back.
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-02-27 14:26:20