Escuché una y otra vez que std::move(t)es más o menos solo una forma elegante de decir static_cast<T&&>(t)y no generaría ninguna instrucción. Cuando estaba jugando ahora con std::moveGodbolt para comprender mejor la semántica de movimiento, vi que genera (o al menos puede) generar instrucciones. En este ejemplo
#include <iostream>
using namespace std;
struct S {
S() { cout << "default ctor" << endl; }
S(S&& s) {
i = s.i;
s.i = 0;
cout << "move ctor" << endl;
}
int i;
};
void foo(S s) { cout << "Foo called with " << s.i << endl; }
int main() {
S s;
foo(static_cast<S&&>(s));
foo(std::move(s));
}
las llamadas para fooconducir a la siguiente salida de ensamblaje
;... snip...
lea rdi, [rbp - 16]
lea rsi, [rbp - 8]
call S::S(S&&) [base object constructor]
lea rdi, [rbp - 16]
call foo(S)
lea rdi, [rbp - 8]
call std::remove_reference<S&>::type&& std::move<S&>(S&)
lea rdi, [rbp - 24]
mov rsi, rax
call S::S(S&&) [base object constructor]
lea rdi, [rbp - 24]
call foo(S)
;... snip...
std::remove_reference<S&>::type&& std::move<S&>(S&): # @std::remove_reference<S&>::type&& std::move<S&>(S&)
push rbp
mov rbp, rsp
mov qword ptr [rbp - 8], rdi
mov rax, qword ptr [rbp - 8]
pop rbp
ret
¿Puede alguien explicarme esto? No tengo mucha idea de lo std::remove_reference<S&>::type&& std::move<S&>(S&)que se supone que debe hacer esta función y por qué existe esta aparente contracción de lo que se dice comúnmente.
Solución del problema
En cuanto a std::remove_reference<S&>::type&& std::move<S&>(S&) Josuttis, explica esto en su semántica de movimientos de C++.
Básicamente, lo que hace es similar static_cast<T&&>pero con los medios de los rasgos de tipo. Permite pasar cualquier categoría de valor (por lo tanto, ya sea lvalue o referencia de rvalue), luego corta la parte de referencia y se aplica a rvalue-ref uno. En cuanto a las instrucciones adicionales: cualquier optimizador debería incluir esas llamadas de todos modos.
Con la optimización desactivada y foodefinida void foo(const S& s);para reducir el ruido:
foo(static_cast<S&&>(s));
leaq -4(%rbp), %rax
movq %rax, %rdi
call foo(S const&)
foo(std::move(s));
leaq -4(%rbp), %rax
movq %rax, %rdi
call std::remove_reference<S&>::type&& std::move<S&>(S&)
movq %rax, %rdi
Con -O1, ambos dan como resultado lo mismo:
leaq 12(%rsp), %rdi
call foo(S const&)
No hay comentarios:
Publicar un comentario