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 przyjmujące odwołanie do wartości, nie bardzo rozumiem, jaki jest cel emplace_back
?
template <class _Valty> void emplace_back(_Valty&& _Val)
wersja, która przyjmuje uniwersalne odniesienie, które zapewnia doskonałe przekazywanie doexplicit
konstruktorów jednoparumentowych .push_back
lepiej jestemplace_back
? Jedyny przypadek, jaki mogę wymyślić, to czy klasa mogłaby być w jakiś sposób możliwa do skopiowania (T&operator=(constT&)
), ale nie nadawała się do konstruowania (T(constT&)
), ale nie mogę wymyślić, dlaczego ktoś tego chciałby.Odpowiedzi:
Oprócz tego, co powiedział odwiedzający:
Funkcja
void emplace_back(Type&& _Val)
zapewniana przez MSCV10 jest niezgodna i redundantna, ponieważ, jak zauważyłeś, jest ściśle równoważna zpush_back(Type&& _Val)
.Ale prawdziwa forma C ++ 0x
emplace_back
jest naprawdę przydatnavoid emplace_back(Args&&...)
:;Zamiast brać
value_type
zmienną, bierze się listę argumentów, co oznacza, że możesz teraz idealnie przekazywać argumenty i konstruować bezpośrednio obiekt w kontenerze bez żadnych tymczasowych.Jest to przydatne, ponieważ bez względu na to, jak sprytne RVO i semantyczne ruchy przynoszą do stołu, wciąż istnieją skomplikowane przypadki, w których push_back prawdopodobnie tworzy niepotrzebne kopie (lub ruchy). Na przykład, za pomocą tradycyjnej
insert()
funkcji astd::map
, musisz utworzyć tymczasowy, który zostanie następnie skopiowany do astd::pair<Key, Value>
, który następnie zostanie skopiowany na mapę:Dlaczego więc nie wdrożyli właściwej wersji Situace_back w MSVC? Właściwie to też dawno mnie zepsuło, więc zadałem to samo pytanie na blogu Visual C ++ . Oto odpowiedź Stephan T. Lavavej, oficjalny opiekun implementacji standardowej biblioteki Visual C ++ w firmie Microsoft.
To zrozumiała decyzja. Każdy, kto choć raz próbował naśladować szablon variadic z okropnymi sztuczkami preprocesora, wie, jak obrzydliwe są te rzeczy.
źródło
pair<const int,Complicated>
nie ma konstruktora, który przyjmuje int, inny int, podwójny i jako czwarty parametr ciąg. Możesz jednak bezpośrednio skonstruować ten obiekt pary za pomocą jego konstruktora częściowego. Oczywiście składnia będzie inna:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
emplace_back
tak długo, jak to zostało wdrożone w Visual C ++ gdy dodano szablony o zmiennej liczbie argumentów: msdn.microsoft.com/en-us/library/hh567368. aspxemplace_back
nie powinien przyjmować argumentu typuvector::value_type
, ale zamiast tego argumenty variadic, które są przekazywane do konstruktora dołączonego elementu.Możliwe jest przekazanie takiego,
value_type
który zostanie przesłany do konstruktora kopii.Ponieważ przekazuje argumenty, oznacza to, że jeśli nie masz wartości, oznacza to, że kontener będzie przechowywać „skopiowaną” kopię, a nie kopię przeniesioną.
Ale powyższe powinno być identyczne z tym, co
push_back
robi. Prawdopodobnie jest raczej przeznaczony do takich przypadków użycia, jak:źródło
s
zakres, czy to nie jest niebezpieczne?vec.emplace_back("Hello")
zadziała, ponieważconst char*
argument zostanie przekazany dostring
konstruktora. To jest sedno sprawyemplace_back
.std::vector
. Pustystd::vector
jest prawidłowym stanem, ale nie można dofront()
niego zadzwonić . Oznacza to, że można wywoływać dowolną funkcję, która nie ma warunków wstępnych (a destruktory nigdy nie mogą mieć warunków wstępnych).Optymalizację dla
emplace_back
można przedstawić w następnym przykładzie.Bo zostanie wywołany
emplace_back
konstruktorA (int x_arg)
. A ponieważpush_back
A (int x_arg)
nazywa się pierwszy, amove A (A &&rhs)
potem nazywa się.Oczywiście konstruktor musi być oznaczony jako
explicit
, ale w obecnym przykładzie dobrze jest usunąć jawność.wynik:
źródło
emplace_back
vspush_back
.v.emplace_back(x);
gdzie x jest jawnie konstruowane przez ruch, ale tylko przez kopiowanie. Fakt, żeemplace_back
jest „niejawnie” jawny, sprawia, że myślę, że prawdopodobnie powinienem przejść do funkcji dołączaniapush_back
. Myśli?a.emplace_back
po raz drugi, zostanie wywołany konstruktor ruchu!Tutaj znajduje się ładny kod dla push_back i Situace_back.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
Operację przenoszenia można zobaczyć na push_back, a nie na Situace_back.
źródło
emplace_back
zgodna implementacja przekaże argumenty dovector<Object>::value_type
konstruktora po dodaniu do wektora. Pamiętam, że Visual Studio nie obsługiwał szablonów variadic, ale szablony variadic będą obsługiwane w Visual Studio 2013 RC, więc sądzę, że zostanie dodany zgodny podpis.Dzięki
emplace_back
, jeśli przekazuje argumenty bezpośrednio dovector<Object>::value_type
konstruktora, nie trzeba typ być ruchomy lub copyable dlaemplace_back
funkcji, ściśle mówiąc. W tymvector<NonCopyableNonMovableObject>
przypadku nie jest to przydatne, ponieważvector<Object>::value_type
do powiększenia wymaga typu kopiowalnego lub ruchomego.Należy jednak pamiętać, że może to być przydatne
std::map<Key, NonCopyableNonMovableObject>
, ponieważ po przydzieleniu wpisu na mapie nie trzeba go już przenosić ani kopiować, w przeciwieństwie dovector
, co oznacza, że możnastd::map
efektywnie używać z typem odwzorowania , którego nie można skopiować ani ruchomy.źródło
Jeszcze jedno w przypadku list:
źródło
Szczególny przypadek użycia dla
emplace_back
: Jeśli chcesz utworzyć obiekt tymczasowy, który zostanie następnie wepchnięty do kontenera, użyjemplace_back
zamiastpush_back
. Stworzy obiekt w miejscu w kontenerze.Uwagi:
push_back
w powyższym przypadku utworzy obiekt tymczasowy i przeniesie go do kontenera. Jednak zastosowana konstrukcja w miejscuemplace_back
byłaby bardziej wydajna niż konstruowanie, a następnie przenoszenie obiektu (co zwykle wymaga pewnego kopiowania).emplace_back
zamiastpush_back
we wszystkich przypadkach bez większego problemu. (Zobacz wyjątki )źródło