Eu vi isso aqui: Move Constructor chamando o Move Constructor de classe base
Alguém poderia explicar:
- a diferença entre
std::move
estd::forward
, de preferência com alguns exemplos de código? - Como pensar sobre isso facilmente e quando usar quais
c++
c++11
perfect-forwarding
aCuria
fonte
fonte
move
quando deseja mover um valor eforward
quando deseja usar o encaminhamento perfeito. Isso não é ciência de foguetes aqui;)Respostas:
std::move
pega um objeto e permite tratá-lo como um temporário (um rvalue). Embora não seja um requisito semântico, normalmente uma função que aceita uma referência a um rvalue o invalidará. Quando você vêstd::move
, indica que o valor do objeto não deve ser usado posteriormente, mas você ainda pode atribuir um novo valor e continuar usando-o.std::forward
possui um único caso de uso: para converter um parâmetro de função de modelo (dentro da função) na categoria de valor (lvalue ou rvalue) que o chamador usou para transmiti-lo. Isso permite que os argumentos rvalue sejam transmitidos como rvalues e lvalues sejam transmitidos como lvalues, um esquema chamado "encaminhamento perfeito".Para ilustrar :
Como Howard menciona, também há semelhanças, já que essas duas funções simplesmente são convertidas para o tipo de referência. Mas fora desses casos de uso específicos (que cobrem 99,9% da utilidade dos modelos de referência rvalue), você deve usar
static_cast
diretamente e escrever uma boa explicação sobre o que está fazendo.fonte
std::forward
o único caso de uso seja o encaminhamento perfeito de argumentos de função. Eu já tive situações em que desejo encaminhar perfeitamente outras coisas, como membros de objetos.Ambos
std::forward
estd::move
nada mais são do que elencos.O exemplo acima converte a expressão lvalue
x
do tipo X para uma expressão rvalue do tipo X (um valor x para ser exato).move
também pode aceitar um rvalue:e, nesse caso, é uma função de identidade: pega um rvalor do tipo X e retorna um rvalor do tipo X.
Com
std::forward
você pode selecionar o destino até certo ponto:Converte a expressão lvalue
x
do tipo X para uma expressão do tipo Y. Há restrições sobre o que Y pode ser.Y pode ser uma base acessível de X, ou uma referência a uma base de X. Y pode ser X ou uma referência a X. Não é possível descartar qualificadores cv com
forward
, mas é possível adicionar qualificadores cv. Y não pode ser um tipo que é meramente conversível em X, exceto por meio de uma conversão Base acessível.Se Y for uma referência lvalue, o resultado será uma expressão lvalue. Se Y não for uma referência de lvalue, o resultado será uma expressão de rvalue (xvalue, para ser preciso).
forward
pode aceitar um argumento rvalue apenas se Y não for uma referência lvalue. Ou seja, você não pode converter um rvalue em lvalue. Por razões de segurança, isso geralmente leva a referências pendentes. Mas converter um rvalue para rvalue é aceitável e permitido.Se você tentar especificar Y para algo que não é permitido, o erro será detectado no tempo de compilação, não no tempo de execução.
fonte
std::forward
, depois que a função for executada, posso usar esse objeto? Estou ciente de que, no caso destd::move
, é um comportamento indefinido.move
: stackoverflow.com/a/7028318/576911 Poisforward
, se você passar um lvalue, sua API deve reagir como se recebesse um lvalue. Normalmente, isso significa que o valor não será modificado. Mas se for um valor não constante, sua API pode ter modificado. Se você passar um rvalue, isso normalmente significa que sua API pode ter sido movida a partir dela e, portanto, seria aplicável o stackoverflow.com/a/7028318/576911 .std::forward
é usado para encaminhar um parâmetro exatamente da maneira como ele foi passado para uma função. Assim como mostrado aqui:Quando usar std :: forward para encaminhar argumentos?
Usar
std::move
oferece um objeto como um rvalue, para possivelmente corresponder a um construtor de movimento ou uma função que aceite rvalues. Isso é feitostd::move(x)
mesmo quex
não seja um valor próprio.fonte