1. "O que é isso?"
Embora std::move()
seja tecnicamente uma função - eu diria que não é realmente uma função . É uma espécie de conversor entre as maneiras pelas quais o compilador considera o valor de uma expressão.
2. "O que isso faz?"
A primeira coisa a notar é que std::move()
, na verdade, não move nada . Ele converte uma expressão de lvalue (como uma variável nomeada) em xvalue . Um xvalue diz ao compilador:
Você pode me pilhar, mover qualquer coisa que eu esteja segurando e usá-la em outro lugar (já que eu vou ser destruído em breve de qualquer maneira) ".
em outras palavras, quando você usa std::move(x)
, está permitindo que o compilador canibalize x
. Portanto, se x
tiver, digamos, seu próprio buffer na memória - depois que std::move()
o compilador puder ter outro objeto, ele será o proprietário.
Você também pode passar de um valor inicial (como um temporário que está passando), mas isso raramente é útil.
3. "Quando deve ser usado?"
Outra maneira de fazer essa pergunta é "Para que eu canibalizaria os recursos de um objeto existente?" bem, se você estiver escrevendo o código do aplicativo, provavelmente não estaria mexendo muito com objetos temporários criados pelo compilador. Então, principalmente, você faria isso em lugares como construtores, métodos de operador, funções semelhantes a algoritmos de biblioteca padrão etc. onde objetos são criados e destruídos muito automagicamente. Claro, isso é apenas uma regra de ouro.
Um uso típico é 'mover' recursos de um objeto para outro em vez de copiar. O @Guillaume fornece links para esta página, que possui um exemplo simples e simples: trocar dois objetos por menos cópias.
template <class T>
swap(T& a, T& b) {
T tmp(a); // we now have two copies of a
a = b; // we now have two copies of b (+ discarded a copy of a)
b = tmp; // we now have two copies of tmp (+ discarded a copy of b)
}
usar move permite trocar os recursos em vez de copiá-los:
template <class T>
swap(T& a, T& b) {
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
}
Pense no que acontece quando T
, digamos, o vector<int>
tamanho n. Na primeira versão, você lê e escreve 3 * n elementos, na segunda versão, basicamente lê e escreve apenas os 3 ponteiros para os buffers dos vetores, além dos tamanhos dos 3 buffers. Claro que classeT
precisa saber como fazer a mudança; sua classe deve ter um operador de atribuição de movimento e um construtor de movimento para que a classe T
funcione.