Estou um pouco confuso sobre a diferença entre push_back
e emplace_back
.
void emplace_back(Type&& _Val);
void push_back(const Type& _Val);
void push_back(Type&& _Val);
Como há uma push_back
sobrecarga tomando uma referência rvalue, não vejo bem qual é o objetivo de emplace_back
se tornar?
template <class _Valty> void emplace_back(_Valty&& _Val)
versão que usa uma referência universal que fornece encaminhamento perfeito paraexplicit
construtores de argumento único.push_back
é preferívelemplace_back
? O único caso em que consigo pensar é se uma classe era de alguma forma copiável (T&operator=(constT&)
), mas não construtiva (T(constT&)
), mas não consigo pensar por que alguém iria querer isso.Respostas:
Além do que o visitante disse:
A função
void emplace_back(Type&& _Val)
fornecida pelo MSCV10 não é conforme e é redundante, porque, como você observou, é estritamente equivalente apush_back(Type&& _Val)
.Mas a verdadeira forma de C ++ 0x de
emplace_back
é realmente útilvoid emplace_back(Args&&...)
:;Em vez de pegar um,
value_type
é preciso uma lista variada de argumentos, o que significa que agora você pode encaminhar perfeitamente os argumentos e construir diretamente um objeto em um contêiner sem um temporário.Isso é útil porque, não importa quanta inteligência o RVO e a movimentação semântica tragam para a tabela, ainda existem casos complicados em que um push_back provavelmente fará cópias desnecessárias (ou mover). Por exemplo, com a
insert()
função tradicional de astd::map
, você deve criar um temporário, que será copiado para astd::pair<Key, Value>
, que será copiado para o mapa:Então, por que eles não implementaram a versão correta do emplace_back no MSVC? Na verdade, isso me incomodou há um tempo atrás, então fiz a mesma pergunta no blog do Visual C ++ . Aqui está a resposta de Stephan T Lavavej, mantenedor oficial da implementação da biblioteca padrão do Visual C ++ na Microsoft.
É uma decisão compreensível. Todo mundo que tentou apenas emular uma vez o modelo variado com truques horríveis do pré-processador sabe como essas coisas ficam nojentas.
fonte
pair<const int,Complicated>
não possui um construtor que usa int, outro int, um double e, como quarto parâmetro, uma string. No entanto, você pode construir diretamente esse objeto de par usando seu construtor por partes. A sintaxe será diferente, é claro:m.emplace(std::piecewise,std::forward_as_tuple(4),std::forward_as_tuple(anInt,aDouble,aString));
emplace_back
, desde que tenha sido implementado no Visual C ++ quando foram adicionados modelos variadosemplace_back
não deve aceitar um argumento do tipovector::value_type
, mas argumentos variados que são encaminhados ao construtor do item anexado.É possível passar um
value_type
que será encaminhado ao construtor de cópias.Como encaminha os argumentos, isso significa que, se você não tiver rvalue, isso ainda significa que o contêiner armazenará uma cópia "copiada", não uma cópia movida.
Mas o acima deve ser idêntico ao que
push_back
faz. Provavelmente é destinado a casos de uso como:fonte
s
de escopo, não é perigoso?vec.emplace_back("Hello")
funcionará, pois oconst char*
argumento será encaminhado aostring
construtor. Este é o ponto principal deemplace_back
.std::vector
. Um vaziostd::vector
é um estado válido, mas você não pode chamáfront()
-lo. Isso significa que qualquer função que não tem pré-condições ainda pode ser chamada (e os destruidores nunca podem ter pré-condições).A otimização para
emplace_back
pode ser demonstrada no próximo exemplo.Para
emplace_back
construtorA (int x_arg)
será chamado. E parapush_back
A (int x_arg)
é chamado primeiro emove A (A &&rhs)
é chamado depois.Obviamente, o construtor deve ser marcado como
explicit
, mas no exemplo atual é bom remover a explicitação.resultado:
fonte
emplace_back
vspush_back
.v.emplace_back(x);
onde x é explicitamente movível-construtível, mas apenas explicitamente copiável-construtível. O fato deemplace_back
ser "implicitamente" explícito me faz pensar que minha função principal de anexar provavelmente deveria serpush_back
. Pensamentos?a.emplace_back
segunda vez, o construtor de movimentação será chamado!Um bom código para push_back e emplace_back é mostrado aqui.
http://en.cppreference.com/w/cpp/container/vector/emplace_back
Você pode ver a operação de movimentação no push_back e não no emplace_back.
fonte
emplace_back
a implementação em conformidade encaminhará argumentos para ovector<Object>::value_type
construtor quando adicionado ao vetor. Lembro-me de que o Visual Studio não suportava modelos variados, mas com modelos variados será suportado no Visual Studio 2013 RC, então acho que uma assinatura conforme será adicionada.Com
emplace_back
, se você encaminhar os argumentos diretamente para ovector<Object>::value_type
construtor, não precisa de um tipo para ser móvel ou copiável para aemplace_back
função, estritamente falando. Novector<NonCopyableNonMovableObject>
caso, isso não é útil, poisvector<Object>::value_type
precisa de um tipo copiável ou móvel para crescer.Mas observe que isso pode ser útil
std::map<Key, NonCopyableNonMovableObject>
, pois, uma vez que você aloca uma entrada no mapa, ela não precisa mais ser movida ou copiada, ao contrário devector
, o que significa que você pode usarstd::map
efetivamente com um tipo mapeado que não é copiável nem móvel.fonte
Mais um no caso de listas:
fonte
Caso de uso específico para
emplace_back
: Se você precisar criar um objeto temporário que será empurrado para um contêiner, use ememplace_back
vez depush_back
. Ele criará o objeto no local dentro do contêiner.Notas:
push_back
no caso acima, criará um objeto temporário e o moverá para o contêiner. No entanto, a construção no local usadaemplace_back
seria mais eficiente do que construir e depois mover o objeto (o que geralmente envolve algumas cópias).emplace_back
vez depush_back
em todos os casos sem muito problema. (Veja exceções )fonte