zoukankan      html  css  js  c++  java
  • C++中lambda的实现(2)

    之前写了一篇C++中的lambda的实现(1),从汇编语言的角度来分析了一下non-mutable lambda的实现方式。这篇文章主要介绍一下mutable lambda的实现方式。而这篇文章中有比较详细的lambda语法示例

    实验用gcc版本4.7.2,据说4.5以前的gcc不能支持C++11中的lambda。

    C++源码

     1 //lambda.cpp
     2 #include <iostream>
     3 using namespace std;
     4 int main(){
     5     int a,b;
     6     a = 1;
     7     b = 2;
     8     auto f = [&a, &b](int c)->int{ a++; b++; return a+b+c;}; //创建一个lambda表达式,'&'表示a, b以引用传递,
    //可以被修改,并且修改会反映到main中的a、b
    9 cout<<"result= "<<f(3)<<endl; 10 cout<<"a= "<<a<<endl; 11 cout<<"b= "<<b<<endl; 12 return 0; 13 }

    编译运行

    g++ -std=c++0x lambda.cpp -o lambda
    ./lambda
    result= 8
    a= 2
    b= 3

    从结果来看,lamba表达式执行之后,a、b的值成功地被修改了。

    下面这一段是main函数6-8行以及f(3)对应的汇编代码,同上次分析的一样,lambda在C++中编译成一个函数。

     1  80487ea:       c7 44 24 10 01 00 00    movl   $0x1,0x10(%esp)  # a=1
     2  80487f1:       00 
     3  80487f2:       c7 44 24 14 02 00 00    movl   $0x2,0x14(%esp)  # b=2
     4  80487f9:       00 
     5  80487fa:       8d 44 24 10             lea    0x10(%esp),%eax
     6  80487fe:       89 44 24 18             mov    %eax,0x18(%esp)  #0x18(%ebp)(记为ref_a)中存放了a的地址
     7  8048802:       8d 44 24 14             lea    0x14(%esp),%eax
     8  8048806:       89 44 24 1c             mov    %eax,0x1c(%esp)  #0x1c(%ebp)(记为ref_b)中存放了b的地址
     9  804880a:       c7 44 24 04 03 00 00    movl   $0x3,0x4(%esp)   #将f(3)中的参数3放在栈上
    10  8048811:       00 
    11  8048812:       8d 44 24 18             lea    0x18(%esp),%eax
    12  8048816:       89 04 24                mov    %eax,(%esp)      #将ref_a的地址放在栈上
    13  8048819:       e8 8e ff ff ff          call   80487ac <_ZZ4mainENKUliE_clEi>  #调用lambda对应的函数

    下面这一段是lambda函数所对应的汇编代码

     80487ac:       55                      push   %ebp
     80487ad:       89 e5                   mov    %esp,%ebp
     80487af:       8b 45 08                mov    0x8(%ebp),%eax         #取出上面一段汇编代码中12行所存的ref_a的地址
     80487b2:       8b 00                   mov    (%eax),%eax            #取出ref_a的值,也就是a的地址
     80487b4:       8b 10                   mov    (%eax),%edx            #取出a的值到edx
     80487b6:       83 c2 01                add    $0x1,%edx              # a++
     80487b9:       89 10                   mov    %edx,(%eax)            #存回a,注意这个时候是存回到了main函数栈上的a里面
     80487bb:       8b 45 08                mov    0x8(%ebp),%eax         #取出ref_a的地址
     80487be:       8b 40 04                mov    0x4(%eax),%eax         #ref_a和ref_b是紧挨着存储的
    #这一条指令取出ref_b的值,也就是b的地址 8
    0487c1: 8b 10 mov (%eax),%edx #取出b的值,放入edx 80487c3: 83 c2 01 add $0x1,%edx # b++ 80487c6: 89 10 mov %edx,(%eax) #存回b 80487c8: 8b 45 08 mov 0x8(%ebp),%eax 80487cb: 8b 00 mov (%eax),%eax 80487cd: 8b 10 mov (%eax),%edx #再取a的值,放在edx 80487cf: 8b 45 08 mov 0x8(%ebp),%eax 80487d2: 8b 40 04 mov 0x4(%eax),%eax 80487d5: 8b 00 mov (%eax),%eax 80487d7: 01 c2 add %eax,%edx #edx = a+b 80487d9: 8b 45 0c mov 0xc(%ebp),%eax #取出上一段汇编中第9行放在站上的参数3 80487dc: 01 d0 add %edx,%eax #eax= a+b+c,而函数返回值放在eax中 80487de: 5d pop %ebp 80487df: c3 ret

    从上面的汇编分析来看,gcc在实现mutable lambda的时候,将lambda的代码编译为函数,将capture list中的可写变量的地址通过一些手段传入到lambda实现函数中。对比之下,non-mutable的lambda则将capture list中变量的值复制一遍,再将复制出来的变量的地址通过一些手段传入lambda实现函数。

  • 相关阅读:
    ExpandableListView实现子Item的点击事件
    使用AndroidStudio自动生成JavaDoc文档
    将Asset中的数据库文件拷贝出来使用
    拦截webview调用系统浏览器打开链接
    配置国内 Docker Registry Mirror
    解决mysql 主从数据库同步不一致的方法
    讯时网关路由规则小结
    Docker 导出 & 导入
    Centos 7 安装Docker-ce记录
    Go Rand小结
  • 原文地址:https://www.cnblogs.com/richardustc/p/2991865.html
Copyright © 2011-2022 走看看