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ę?

Author: Ajay, 2010-11-29

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.

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.

To zrozumiała decyzja. Każdy, kto choć raz próbował emulować różne szablony za pomocą preprocesora, wie, jak obrzydliwe staje się to.
 440
Author: Thomas Petit,
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
 160
Author: visitor,
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 &&)
 43
Author: vadikrobot,
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_typepo 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.

 7
Author: Germán Diago,
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"});

 1
Author: ,
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-12-28 10:15:28

Ł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.

 1
Author: Dharma,
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