我一再听说std::move(t)
或多或少只是static_cast<T&&>(t)
的一种奇特表达方式,不会生成任何指令。当我现在在godbolt上玩std::move
时,为了更好地理解移动语义,我看到它确实(或者至少可能(生成指令。在本例中,
#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));
}
对foo
的调用导致下面的汇编输出
; ... 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
有人能给我解释一下吗?我不太清楚这个std::remove_reference<S&>::type&& std::move<S&>(S&)
函数应该做什么,也不太清楚为什么会有这种明显的收缩。
对于std::remove_reference<S&>::type&& std::move<S&>(S&)
Josuttis在他的C++移动语义中解释了这一点。
它的作用基本上类似于static_cast<T&&>
,但具有类型特征。它允许传入任何值类别(因此,左值或右值引用(,然后切断引用部分并应用于右值引用一。至于额外的指令:任何优化器都应该内联这些调用。
关闭优化并将foo
定义为void foo(const S& s);
以降低噪声:
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
对于-O1
,两者的结果相同:
leaq 12(%rsp), %rdi
call foo(S const&)
编译时没有进行优化。因此,您可以准确地看到所写的内容,而无需任何简化或内联函数的尝试。
生成的代码大致等于type&& foo(type& x) { return x; }
将生成的代码,move
就是这样做的。
研究在没有打开优化的情况下生成的程序集是徒劳的。