C++11新特性中的匿名函数Lambda表达式的汇编实现分析(二)-阿里云开发者社区

开发者社区> 青衫无名> 正文

C++11新特性中的匿名函数Lambda表达式的汇编实现分析(二)

简介:
+关注继续查看

首先,让我们来看看以&方式进行变量捕获,同样没有参数和返回。

int main()
{
    int a = 0xB;
    auto lambda = [&]{
        a = 0xA;
    };
    lambda();
    return 0;
}

闭包中将main中a变量改写为0xA。

main中的关键汇编代码:

int a = 0xB;
 mov         dword ptr [ebp-8],0Bh  
    auto lambda = [&]{
        a = 0xA;
    };
 lea         eax,[ebp-8]  
 push        eax  
 lea         ecx,[ebp-14h]  
 call        002D1BE0  
    lambda();
 lea         ecx,[ebp-14h]  
 call        002D1C20  
    return 0;

同样的,进入闭包前要调用一个拷贝函数。

002D1BE0 内:

pop         ecx  
 mov         dword ptr [ebp-8],ecx  
 mov         eax,dword ptr [ebp-8]  
 mov         ecx,dword ptr [ebp+8]  
 mov         dword ptr [eax],ecx  
 mov         eax,dword ptr [ebp-8]  
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         esp,ebp  
 pop         ebp  
 ret         4

和前面一篇文章中的代码基本一致,但是有两个地方不同,

上文写到:

pop         ecx  

 mov         dword ptr [ebp-8],ecx  

 mov         eax,dword ptr [ebp-8]  

 mov         ecx,dword ptr [ebp+8]  

 mov         edx,dword ptr [ecx]  

 mov         dword ptr [eax],edx  

 mov         eax,dword ptr [ebp-8]

注意黑体部分,若采用[=]的捕获方式,那么将通过寄存器edx拷贝原变量的值;

若采用[&]方式,则直接通过ecx拷贝原变量的地址,而不取出值。

闭包内:

pop         ecx  
 mov         dword ptr [ebp-8],ecx  
        a = 0xA;
 mov         eax,dword ptr [ebp-8]  
 mov         ecx,dword ptr [eax]  
 mov         dword ptr [ecx],0Ah  
    };
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         esp,ebp  
 pop         ebp  
 ret

对a进行赋值,直接是:

*this = 0xA;

因为事先this就取到了a的地址。

可以发现,按引用捕获实际上就如同函数参数传递引用,传递的是一个地址值,而不创建对象副本(可以和上一篇文中的内容比较)。

C++11标准中对Lambda表达式的捕获内容还有一些特定支持,比如可以以指定的方式捕获指定的变量:

int main()
{
    int a = 0xB;
    bool b = true;
    auto lambda = [&a,b]{
        a = b;
    };
    lambda();
    return 0;
}

上面的代码对a进行引用捕获,对b按值捕获。根据前面分析的结果,可以预见,a的地址和b的值将被拷贝以供闭包函数使用。

int a = 0xB;
 mov         dword ptr [ebp-8],0Bh  
    bool b = true;
 mov         byte ptr [ebp-11h],1  
    auto lambda = [&a,b]{
        a = b;
    };
 lea         eax,[ebp-11h]  
 push        eax  
 lea         ecx,[ebp-8]  
 push        ecx  
 lea         ecx,[ebp-24h]  
 call        00222060  
    lambda();
 lea         ecx,[ebp-24h]  
    lambda();
 call        00221C20  
    return 0;

调用Lambda之前,先调用复制函数,传入两个参数,&a和&b,而this被放在main的[ebp-24h]中。

复制函数或者叫准备函数:

pop         ecx  
 mov         dword ptr [ebp-8],ecx  
 mov         eax,dword ptr [ebp-8]  
 mov         ecx,dword ptr [ebp+8]  
 mov         dword ptr [eax],ecx  
 mov         eax,dword ptr [ebp-8]  
 mov         ecx,dword ptr [ebp+0Ch]  
 mov         dl,byte ptr [ecx]  
 mov         byte ptr [eax+4],dl  
 mov         eax,dword ptr [ebp-8]  
 pop         edi  
 pop         esi  
 pop         ebx  
 mov         esp,ebp  
 pop         ebp  
 ret         8

[eax] 就是 *this,也即a

[eax+4] 就是 *(this+4),也即b

从内存图可以清楚的看到,a的地址被记录,b的值被复制

image

闭包函数内:

pop         ecx  
 mov         dword ptr [ebp-8],ecx  
        a = b;
 mov         eax,dword ptr [ebp-8]  
 movzx       ecx,byte ptr [eax+4]  
 
 mov         edx,dword ptr [ebp-8]  
 mov         eax,dword ptr [edx]  
 mov         dword ptr [eax],ecx

b的值是从[eax+4]也即this+4中取出,而a在this中,其实就是:

*(this) = *(this+4);

可以看到闭包内通过this作为基址,对闭包外的变量进行偏移访问。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
HSF/Dubbo序列化时的LocalDateTime, Instant的性能问题
### 来源 在对Dubbo新版本做性能压测时,无意中发现对用例中某个TO(Transfer Object)类的一属性字段稍作修改,由Date变成LocalDateTime,结果是吞吐量由近5w变成了2w,RT由9ms升指90ms。
2331 0
独家揭秘:阿里小程序的一云多端!看这篇就够了!
阿里巴巴小程序一云多端的整体战略,以及阿里小程序后续为开发者提供的云服务(云应用、云开发等)、开发者工具链(IDE、插件、SDK等)、跨端框架能力说明。同时结合繁星计划后续提供给开发者的扶持和ISV的权益体系做一个整体的介绍。
27362 0
mac vagrant 创建 lnmp 开发环境
建议使用迅雷下载,浏览器下载可能太慢。123实操笔记mac homebrew 安装 vagrant$ brew cask install vagrantCloning into '/usr/local/Homebrew/Library/Taps/homebrew/homebrew-cask'.
590 0
CDN的HTTPS配置及故障排除
相较于HTTP协议来说,HTTPS协议在网络链路中传输更具有安全可靠性,因为它通过SSL证书在链路中间对我们七层的网络包做了加密,进而防止了一些恶意的内容劫持。针对于这种场景,阿里云CDN也提供了相关的功能,可以支持客户端到CDN L1节点的HTTPS的协议。
1574 0
GDB 调试 Mysql 实战(一)源码编译安装
下载源码 git clone https://github.com/mysql/mysql-server.git cd mysql-server git checkout 5.7 编译安装 安装依赖 yum install -y cmake make gcc gcc-c++ ncurses-dev...
979 0
PostgreSQL 锁
锁的类型 /* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */ #define NoLock 0 #define AccessS...
1138 0
+关注
3598
文章
840
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载