对比一段代码:
int main()
{
int dd= 0x123456;
int cd = 0x654321;
dd = cd;
return 0;
}
汇编:
int dd= 0x123456;
4005b4: c7 45 fc 56 34 12 00 movl $0x123456,-0x4(%rbp)//rbp-0x4位置定义临时变量dd
int cd = 0x654321;
4005bb: c7 45 f8 21 43 65 00 movl $0x654321,-0x8(%rbp)// rbp - 0x8位置定义临时变量cd
dd = cd;
4005c2: 8b 45 f8 mov -0x8(%rbp),%eax// 吧cd 拷贝到数据寄存器eax
4005c5: 89 45 fc mov %eax,-0x4(%rbp)//把eax拷贝到rbp-0x4位置
return 0;
4005c8: b8 00 00 00 00 mov $0x0,%eax
和
int main()
{
int &&dd= 0x123456;
int cd = 0x654321;
dd = cd;
return 0;
}
汇编:
int &&dd= 0x123456;
4005b4: b8 56 34 12 00 mov $0x123456,%eax// 把数据值0x123456存储到eax
4005b9: 89 45 f0 mov %eax,-0x10(%rbp)// 申请一个临时的int变量空间rbp - 0x10 ,并把eax值填进去
4005bc: 48 8d 45 f0 lea -0x10(%rbp),%rax// 把临时对象的地址拷贝到rax中
4005c0: 48 89 45 f8 mov %rax,-0x8(%rbp)// 把临时对象的地址拷贝到临时对象rbp-0x8位置处
int cd = 0x654321;
4005c4: c7 45 f4 21 43 65 00 movl $0x654321,-0xc(%rbp)//申请临时对象,并把0x654321值填进去
dd = cd;
4005cb: 48 8b 45 f8 mov -0x8(%rbp),%rax// 把前面存储的临时对象的地址读取到rax中
4005cf: 8b 55 f4 mov -0xc(%rbp),%edx//
4005d2: 89 10 mov %edx,(%rax)// 把edx中的值赋值给rax寻址的地址
return 0;
再来看一下返回对象的对比:
D &&d = Get();
d.t = 0x789;
printf("d.t %d.\n",d.t);
return 0;
D d = Get();
d.t = 0x789;
printf("d.t %d.\n",d.t);
return 0;
可以看出来,上面的构造函数和Get函数都没有区别,唯独右值引用的时候少了一次临时对象地址拷贝的过程
传递参数的时候是一样的道理:看代码
void PRINT(D &&d)
{
printf("d.t %x.\n",d.t);
}
void PRINT1(D d)
{
printf("d.t %x.\n",d.t);
}
这两函数的汇编实现是一样的
调用时候对应的汇编:
D d{0x1234567};
4007b2: 48 8d 45 d0 lea -0x30(%rbp),%rax
4007b6: be 67 45 23 01 mov $0x1234567,%esi
4007bb: 48 89 c7 mov %rax,%rdi
4007be: e8 9b 00 00 00 callq 40085e <_ZN1DC1Ei>
PRINT(std::move(d));
4007c3: 48 8d 45 d0 lea -0x30(%rbp),%rax
4007c7: 48 89 c7 mov %rax,%rdi
4007ca: e8 bd 00 00 00 callq 40088c <_ZSt4moveIR1DEONSt16remove_referenceIT_E4typeEOS3_>
4007cf: 48 89 c7 mov %rax,%rdi
4007d2: e8 88 ff ff ff callq 40075f <_Z5PRINTO1D>
PRINT1(d);
4007d7: 8b 45 d0 mov -0x30(%rbp),%eax
4007da: 89 45 e0 mov %eax,-0x20(%rbp)//申请临时对象吧对象的地址转存一下
4007dd: 48 8d 45 e0 lea -0x20(%rbp),%rax// 吧对象地址存到rax
4007e1: 48 89 c7 mov %rax,%rdi
4007e4: e8 9b ff ff ff callq 400784 <_Z6PRINT11D>
4007e9: 48 8d 45 e0 lea -0x20(%rbp),%rax
4007ed: 48 89 c7 mov %rax,%rdi
4007f0: e8 7f 00 00 00 callq 400874 <_ZN1DD1Ev>
上面两个函数实现的代码一样的,
void PRINT(D &&d)
{
40075f: 55 push %rbp
400760: 48 89 e5 mov %rsp,%rbp
400763: 48 83 ec 10 sub $0x10,%rsp
400767: 48 89 7d f8 mov %rdi,-0x8(%rbp)
printf("d.t %x.\n",d.t);
40076b: 48 8b 45 f8 mov -0x8(%rbp),%rax
40076f: 8b 00 mov (%rax),%eax
400771: 89 c6 mov %eax,%esi
400773: bf 46 09 40 00 mov $0x400946,%edi
400778: b8 00 00 00 00 mov $0x0,%eax
40077d: e8 6e fe ff ff callq 4005f0 <printf@plt>
}
400782: c9 leaveq
400783: c3 retq
0000000000400784 <_Z6PRINT11D>:
void PRINT1(D d)
{
400784: 55 push %rbp
400785: 48 89 e5 mov %rsp,%rbp
400788: 48 83 ec 10 sub $0x10,%rsp
40078c: 48 89 7d f8 mov %rdi,-0x8(%rbp)
printf("d.t %x.\n",d.t);
400790: 48 8b 45 f8 mov -0x8(%rbp),%rax
400794: 8b 00 mov (%rax),%eax
400796: 89 c6 mov %eax,%esi
400798: bf 46 09 40 00 mov $0x400946,%edi
40079d: b8 00 00 00 00 mov $0x0,%eax
4007a2: e8 49 fe ff ff callq 4005f0 <printf@plt>
}
不同的是调用的时候,一个传递的对象地址,一个传递的是一个临时生成的对象的地址。临时对象是由原来的对象复制出来的