A std::move(x)
função C ++ 11 realmente não move nada. É apenas um lançamento para o valor r. Por que isso foi feito? Isso não é enganoso?
c++
c++11
move-semantics
rvalue-reference
c++-faq
Howard Hinnant
fonte
fonte
std::move
realmente se move ..std::char_traits::move
:-)std::remove()
que não remove os elementos: você ainda precisa ligarerase()
para remover esses elementos do contêiner. Entãomove
não se move,remove
não remove. Eu teria escolhido o nomemark_movable()
paramove
.mark_movable()
confuso. Isso sugere que há um efeito colateral duradouro, onde na verdade não existe.Respostas:
É correto que
std::move(x)
seja apenas uma conversão para rvalue - mais especificamente para um xvalue , em oposição a um prvalue . E também é verdade que ter um elenco chamadomove
às vezes confunde as pessoas. No entanto, a intenção dessa nomeação não é confundir, mas sim tornar seu código mais legível.A história
move
remonta à proposta original de mudança em 2002 . Este artigo apresenta primeiro a referência rvalue e, em seguida, mostra como escrever uma descrição mais eficientestd::swap
:É preciso lembrar que, neste ponto da história, a única coisa que "
&&
" poderia significar era lógica e . Ninguém estava familiarizado com as referências rvalue, nem com as implicações de converter um lvalue em um rvalue (sem fazer uma cópia comostatic_cast<T>(t)
faria). Portanto, os leitores desse código pensariam naturalmente:Observe também que
swap
é realmente apenas um substituto para todos os tipos de algoritmos de modificação de permutação. Essa discussão é muito , muito maior queswap
.Em seguida, a proposta introduz o açúcar de sintaxe, que substitui o
static_cast<T&&>
por algo mais legível que transmite não o que é preciso , mas o porquê :Ou seja,
move
é apenas o açúcar da sintaxestatic_cast<T&&>
, e agora o código é bastante sugestivo sobre o porquê desses elencos existem: ativar a semântica de movimento!É preciso entender que, no contexto da história, poucas pessoas realmente entenderam a conexão íntima entre rvalues e semântica de movimento (embora o artigo tente explicar isso também):
Se na época
swap
fosse apresentado assim:Então as pessoas teriam olhado para isso e dito:
O ponto principal:
Como era
move
, ninguém nunca perguntou:Com o passar dos anos e a proposta foi refinada, as noções de lvalue e rvalue foram refinadas nas categorias de valor que temos hoje:
(imagem descaradamente roubada de dirkgently )
E então hoje, se quiséssemos
swap
dizer com precisão o que está fazendo, em vez de por que , deveria parecer mais:E a pergunta que todos deveriam se perguntar é se o código acima é mais ou menos legível do que:
Ou até o original:
De qualquer forma, o programador C ++ deve saber que, sob o capô de
move
, nada mais está acontecendo do que um elenco. E o programador iniciante em C ++, pelo menos commove
, será informado de que a intenção é sair do rhs, em vez de copiar do rhs, mesmo que eles não entendam exatamente como isso é realizado.Além disso, se um programador desejar essa funcionalidade com outro nome, ele
std::move
não possuirá monopólio dessa funcionalidade e não haverá mágica de linguagem não portátil envolvida em sua implementação. Por exemplo, se alguém quiser codificarset_value_category_to_xvalue
e usar isso, é trivial fazer isso:No C ++ 14, fica ainda mais conciso:
Portanto, se você é tão inclinado, decore o
static_cast<T&&>
que achar melhor e, talvez, acabe desenvolvendo uma nova melhor prática (o C ++ está em constante evolução).Então, o que
move
faz em termos de código de objeto gerado?Considere isto
test
:Compilado com
clang++ -std=c++14 test.cpp -O3 -S
, isso produz este código de objeto:Agora, se o teste for alterado para:
Não há absolutamente nenhuma alteração no código do objeto. Pode-se generalizar esse resultado para: Para objetos trivialmente móveis ,
std::move
não tem impacto.Agora vamos ver este exemplo:
Isso gera:
Se você executar
__ZN1XaSERKS_
atravésc++filt
ela produz:X::operator=(X const&)
. Nenhuma surpresa aqui. Agora, se o teste for alterado para:Ainda não há nenhuma alteração no código do objeto gerado.
std::move
fez nada além de converterj
em um rvalue e, em seguida, esse rvalueX
se liga ao operador de atribuição de cópia deX
.Agora vamos adicionar um operador de atribuição de movimento a
X
:Agora o código objeto faz a mudança:
Correndo
__ZN1XaSEOS_
atravésc++filt
revela queX::operator=(X&&)
está sendo chamado em vez deX::operator=(X const&)
.E é só isso
std::move
! Desaparece completamente em tempo de execução. Seu único impacto é no tempo de compilação, onde pode alterar a sobrecarga chamada.fonte
digraph D { glvalue -> { lvalue; xvalue } rvalue -> { xvalue; prvalue } expression -> { glvalue; rvalue } }
para o bem público :) Faça o download aqui como SVGallow_move
;)movable
.std::move
pararvalue_cast
: youtube.com/…rvalue_cast
é ambíguo em seu significado: que tipo de rvalor ele retorna?xvalue_cast
seria um nome consistente aqui. Infelizmente, a maioria das pessoas, neste momento, também não entenderia o que está fazendo. Em mais alguns anos, espero que minha declaração se torne falsa.Deixe-me deixar aqui uma citação da FAQ do C ++ 11, escrita por B. Stroustrup, que é uma resposta direta à pergunta do OP:
A propósito, gostei muito do FAQ - vale a pena ler.
fonte