C++11 深度理解右值引用

对比一段代码:

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>
}

不同的是调用的时候,一个传递的对象地址,一个传递的是一个临时生成的对象的地址。临时对象是由原来的对象复制出来的

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值