Em C ++ 11 emplace_back()
geralmente é preferível (em termos de eficiência) push_back()
, pois permite a construção no local, mas ainda é o caso ao usar push_back(std::move())
com um objeto já construído?
Por exemplo, emplace_back()
ainda é preferido em casos como o seguinte?
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)
Além disso, há alguma vantagem no exemplo acima em fazer:
myvector.emplace_back(std::move(mystring));
ou a mudança aqui é totalmente redundante ou não tem efeito?
c++11
move-semantics
push-back
emplace
Tumulto
fonte
fonte
myvector.emplace_back(mystring);
copia e não se move. Os outros dois movimentos e devem ser equivalentes.Respostas:
Vamos ver o que as diferentes chamadas fornecidas por você fazem:
emplace_back(mystring)
: Esta é uma construção no local do novo elemento com qualquer argumento fornecido. Uma vez que você forneceu um lvalue, essa construção no local na verdade é uma construção de cópia, ou seja, isso é o mesmo que chamarpush_back(mystring)
push_back(std::move(mystring))
: Isso chama a inserção de movimento, que no caso de std :: string é uma construção de movimento no local.emplace_back(std::move(mystring))
: Novamente, esta é uma construção in-loco com os argumentos que você forneceu. Uma vez que esse argumento é um rvalue, ele chama o construtor de movimento destd::string
, ou seja, é uma construção de movimento no local como em 2.Em outras palavras, se chamados com um argumento do tipo T, seja um rvalue ou lvalue,
emplace_back
epush_back
são equivalentes.No entanto, para qualquer outro argumento (s),
emplace_back
vence a corrida, por exemplo com umchar const*
em avector<string>
:emplace_back("foo")
requerstring::string(char const*)
construção no local.push_back("foo")
primeiro tem que chamarstring::string(char const*)
a conversão implícita necessária para corresponder à assinatura da função e, em seguida, uma inserção de movimento como o caso 2. acima. Portanto, é equivalente apush_back(string("foo"))
fonte
s
pode ser definido como uma referência de rvalue que se liga apenas a rvalues, mas dentro defoo
,s
é um lvalue.O emplace_back obtém uma lista de referências de rvalue e tenta construir um elemento de contêiner direto no local. Você pode chamar emplace_back com todos os tipos que os construtores de elemento de contêiner suportam. Ao chamar emplace_back para parâmetros que não são referências rvalue, ele 'retorna' às referências normais e pelo menos o construtor de cópia é chamado quando o parâmetro e os elementos do contêiner são do mesmo tipo. No seu caso, 'myvector.emplace_back (mystring)' deve fazer uma cópia da string porque o compilador não pode saber que o parâmetro myvector é móvel. Portanto, insira o std :: move o que lhe dá o benefício desejado. O push_back deve funcionar tão bem quanto emplace_back para elementos já construídos.
fonte