聊聊Lamda

最近开始看C++11的新语法,觉得有些知识还是要更进一步认识下,下面仅就这段简短的代码来聊聊Lamda,为啥在这段代码里面 lamda中的x 是 10 而不是 15呢? 

int testFun() {
    int x = 10;
    int y = 20;
    int ret = 0;
    auto f = [x, &y] ()-> int {
        y++;
        return x+y;
    };
    x = 15;
    y = 100;
    ret = f();
    return ret;
}

上面这段代码,返回的ret = 111, 而不是 116,这个是为啥呢?

以下是它的ARM 汇编代码(没办法,其它架构不熟悉,只能拿ARM汇编来分析 :-  ))

.text:00008AD4 ; =============== S U B R O U T I N E =======================================
.text:00008AD4
.text:00008AD4
.text:00008AD4 ; _DWORD testFun(void)
.text:00008AD4                 EXPORT _Z7testFunv
.text:00008AD4 _Z7testFunv                             ; CODE XREF: testFun(void)+8j
.text:00008AD4                                         ; DATA XREF: .got:_Z7testFunv_ptro
.text:00008AD4
.text:00008AD4 var_28          = -0x28
.text:00008AD4 var_24          = -0x24
.text:00008AD4 var_20          = -0x20
.text:00008AD4 var_1C          = -0x1C
.text:00008AD4 var_18          = -0x18
.text:00008AD4 var_14          = -0x14
.text:00008AD4 var_10          = -0x10
.text:00008AD4 var_C           = -0xC
.text:00008AD4
.text:00008AD4                 PUSH            {R7,LR}
.text:00008AD6                 MOV             R7, SP
.text:00008AD8                 SUB             SP, SP, #0x20
.text:00008ADA                 LDR             R0, =(__stack_chk_guard_ptr - 0x8AE0)
.text:00008ADC                 ADD             R0, PC ; __stack_chk_guard_ptr
.text:00008ADE                 LDR             R0, [R0] ; __stack_chk_guard
.text:00008AE0                 LDR             R1, [R0]
.text:00008AE2                 STR             R1, [SP,#0x28+var_C]
.text:00008AE4                 MOVS            R1, #0xA
.text:00008AE6                 STR             R1, [SP,#0x28+var_1C]
.text:00008AE8                 MOVS            R1, #0x14
.text:00008AEA                 STR             R1, [SP,#0x28+var_10]
.text:00008AEC                 MOVS            R1, #0
.text:00008AEE                 STR             R1, [SP,#0x28+var_20]
.text:00008AF0                 LDR             R1, [SP,#0x28+var_1C]
.text:00008AF2                 STR             R1, [SP,#0x28+var_18]
.text:00008AF4                 ADD             R1, SP, #0x28+var_10
.text:00008AF6                 STR             R1, [SP,#0x28+var_14]
.text:00008AF8                 MOVS            R1, #0xF
.text:00008AFA                 STR             R1, [SP,#0x28+var_1C]
.text:00008AFC                 MOVS            R1, #0x64
.text:00008AFE                 STR             R1, [SP,#0x28+var_10]
.text:00008B00                 ADD             R1, SP, #0x28+var_18
.text:00008B02                 STR             R0, [SP,#0x28+var_24]
.text:00008B04                 MOV             R0, R1
.text:00008B06                 BL              sub_8B2C
.text:00008B0A                 STR             R0, [SP,#0x28+var_20]
.text:00008B0C                 LDR             R0, [SP,#0x28+var_20]
.text:00008B0E                 LDR             R1, [SP,#0x28+var_24]
.text:00008B10                 LDR.W           LR, [R1]
.text:00008B14                 LDR             R2, [SP,#0x28+var_C]
.text:00008B16                 CMP             LR, R2
.text:00008B18                 STR             R0, [SP,#0x28+var_28]
.text:00008B1A                 BNE             loc_8B24
.text:00008B1C                 B               loc_8B1E
.text:00008B1E ; ---------------------------------------------------------------------------
.text:00008B1E
.text:00008B1E loc_8B1E                                ; CODE XREF: testFun(void)+48j
.text:00008B1E                 LDR             R0, [SP,#0x28+var_28]
.text:00008B20                 ADD             SP, SP, #0x20
.text:00008B22                 POP             {R7,PC}
.text:00008B24 ; ---------------------------------------------------------------------------
.text:00008B24
.text:00008B24 loc_8B24                                ; CODE XREF: testFun(void)+46j
.text:00008B24                 BLX             __stack_chk_fail
.text:00008B24 ; End of function testFun(void)
.text:00008B24
.text:00008B24 ; ---------------------------------------------------------------------------
.text:00008B28 off_8B28        DCD __stack_chk_guard_ptr - 0x8AE0
.text:00008B28                                         ; DATA XREF: testFun(void)+6r
.text:00008B2C
.text:00008B2C ; =============== S U B R O U T I N E =======================================
.text:00008B2C
.text:00008B2C
.text:00008B2C sub_8B2C                                ; CODE XREF: testFun(void)+32p
.text:00008B2C
.text:00008B2C var_8           = -8
.text:00008B2C var_4           = -4
.text:00008B2C
.text:00008B2C                 SUB             SP, SP, #8
.text:00008B2E                 MOV             R1, R0
.text:00008B30                 STR             R0, [SP,#8+var_4]
.text:00008B32                 LDR             R0, [SP,#8+var_4]
.text:00008B34                 LDR             R2, [R0,#4]
.text:00008B36                 LDR             R3, [R2]
.text:00008B38                 ADDS            R3, #1
.text:00008B3A                 STR             R3, [R2]
.text:00008B3C                 LDR             R2, [R0]
.text:00008B3E                 LDR             R0, [R0,#4]
.text:00008B40                 LDR             R0, [R0]
.text:00008B42                 ADD             R0, R2
.text:00008B44                 STR             R1, [SP,#8+var_8]
.text:00008B46                 ADD             SP, SP, #8
.text:00008B48                 BX              LR
.text:00008B48 ; End of function sub_8B2C
.text:00008B48
.text:00008B48 ; ---------------------------------------------------------------------------

下面我们分析整个过程,堆栈的变化如下:

高地址    
0x20    
0x1c    
0x180x140x64  
0x14y的地址(SP+0x18)   
0x10x内容的拷贝(0xA) R0 
0xc0xA0xF  
0x80x0  结果写到这个地址
0x4 R0  
SP    
   原SP+0x10地址 
SP   R2是原SP+0x14地址
R3是上述地址的内容

执行Lamda表达式实际跟调用函数基本也没啥区别,编译的时候还是给编译成单独的函数调用过程,如下是用BL调用过程 在执行.text:00008AFE                 STR             R1, [SP,#0x28+var_10]  之后,实际堆栈入红色部分第2列所示,我们看到实际上对lamda表达式中的[x, &y]实际就是 SP+0x10 和SP+0x14 地址的内容,它们就是我们赋值的 0xA 和 原SP+0x18。

在这里需要特别注意下:

.text:00008AF0                 LDR             R1, [SP,#0x28+var_1C]
.text:00008AF2                 STR             R1, [SP,#0x28+var_18]
.text:00008AF4                 ADD             R1, SP, #0x28+var_10
.text:00008AF6                 STR             R1, [SP,#0x28+var_14]

在这里,前面两句是操作地址对应的内容,也就是x拷贝了一份到SP+0x10地址,后面这个实际是将y的地址写入到SP+0x14的地址。之后R0指向地址SP+0x10,并且我们调用了子函数,也就是lamda函数,

.text:00008B06                 BL              sub_8B2C

在具体的函数内部,也是会去压栈和出栈。对应的是黄色的部分。我们看下函数的R0,实际是指向原先的SP+0x10,对应的内容是x变量的拷贝,它的下一个单元SP+0x14实际就是y变量的地址。关于sub_8B2C内容,解释也就是很简单了。

总结以下,对于lamda来说,中括号里面的只要不带 &, 那么就表示这个变量是原变量的一个拷贝,外部变量的变化,不会影响lamda里面的变化,lamda只关心定义这个的时候的具体数值。而带上&,则表示这个变量是原变量的别名,原变量发生变化,会影响这个变量,同理这个变量发生变化,也会引发原变量的变化。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值