C++11 中的 Lambda 表达式原理

468 阅读4分钟

C++11 中的 Lambda 表达式

  • C++11 中 Lambda 表达式本质上就是一段 机器代码(Code)
  • 通过 callq 机器指令进行 Lambda函数 的调用

C++11 中 Lambda 表达式的实现

Lambda 表达式使用

如下所示:

#include <iostream>
int main() {

    /*
     * 无参无返回值的 lambda 表达式
     */
    auto hello = []() -> void{
        std::cout << "Hello, World!" << std::endl;
    };

    /*
     * 带参带返回值的 lambda 表达式
     */
    auto printI = [](int i) -> int {
        std::cout << "printI:" << i << std::endl;
        return i;
    };

    /*
     * lambda 表达式的调用
     */
    hello();
    int result = printI(5);
    std::cout << "result is :"<< result <<std::endl;

    return 0;
}


Lambda 表达式反汇编分析

Lambda 函数的调用

main() 函数,反汇编后的汇编代码如下所示

通过 callq 指令,跳转到对应的 代码段 Code 中去

Dump of assembler code for function main():
   0x00000000080009fe <+0>:     push   %rbp
   0x00000000080009ff <+1>:     mov    %rsp,%rbp
   0x0000000008000a02 <+4>:     sub    $0x10,%rsp
   0x0000000008000a06 <+8>:     mov    %fs:0x28,%rax
   0x0000000008000a0f <+17>:    mov    %rax,-0x8(%rbp)
   0x0000000008000a13 <+21>:    xor    %eax,%eax
   0x0000000008000a15 <+23>:    lea    -0xe(%rbp),%rax
   0x0000000008000a19 <+27>:    mov    %rax,%rdi
=> 0x0000000008000a1c <+30>:    callq  0x800097a <<lambda()>::operator()(void) const>
   0x0000000008000a21 <+35>:    lea    -0xd(%rbp),%rax
   0x0000000008000a25 <+39>:    mov    $0x5,%esi
   0x0000000008000a2a <+44>:    mov    %rax,%rdi
   0x0000000008000a2d <+47>:    callq  0x80009b2 <<lambda(int)>::operator()(int) const>
   0x0000000008000a32 <+52>:    mov    %eax,-0xc(%rbp)
   0x0000000008000a35 <+55>:    lea    0x14f(%rip),%rsi        # 0x8000b8b
   0x0000000008000a3c <+62>:    lea    0x2015dd(%rip),%rdi        # 0x8202020 <_ZSt4cout@@GLIBCXX_3.4>
   0x0000000008000a43 <+69>:    callq  0x8000810 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x0000000008000a48 <+74>:    mov    %rax,%rdx
   0x0000000008000a4b <+77>:    mov    -0xc(%rbp),%eax
   0x0000000008000a4e <+80>:    mov    %eax,%esi
   0x0000000008000a50 <+82>:    mov    %rdx,%rdi
   0x0000000008000a53 <+85>:    callq  0x8000850 <_ZNSolsEi@plt>
   0x0000000008000a58 <+90>:    mov    %rax,%rdx
   0x0000000008000a5b <+93>:    mov    0x20156e(%rip),%rax        # 0x8201fd0
   0x0000000008000a62 <+100>:   mov    %rax,%rsi
   0x0000000008000a65 <+103>:   mov    %rdx,%rdi
   0x0000000008000a68 <+106>:   callq  0x8000820 <_ZNSolsEPFRSoS_E@plt>
   0x0000000008000a6d <+111>:   mov    $0x0,%eax
   0x0000000008000a72 <+116>:   mov    -0x8(%rbp),%rcx
   0x0000000008000a76 <+120>:   xor    %fs:0x28,%rcx
   0x0000000008000a7f <+129>:   je     0x8000a86 <main()+136>
   0x0000000008000a81 <+131>:   callq  0x8000830 <__stack_chk_fail@plt>
   0x0000000008000a86 <+136>:   leaveq
   0x0000000008000a87 <+137>:   retq
End of assembler dump.

Lambda 函数的组成
/*
* 无参无返回值的 lambda 表达式
*/
auto hello = []() -> void{
    std::cout << "Hello, World!" << std::endl;
};

上述 Lambda 函数反汇编后的汇编代码如下

直接开辟新的 栈帧(Frame) 执行函数代码

Dump of assembler code for function <lambda()>::operator()(void) const:
=> 0x000000000800097a <+0>:     push   %rbp
   0x000000000800097b <+1>:     mov    %rsp,%rbp
   0x000000000800097e <+4>:     sub    $0x10,%rsp
   0x0000000008000982 <+8>:     mov    %rdi,-0x8(%rbp)
   0x0000000008000986 <+12>:    lea    0x1e8(%rip),%rsi        # 0x8000b75
   0x000000000800098d <+19>:    lea    0x20168c(%rip),%rdi        # 0x8202020 <_ZSt4cout@@GLIBCXX_3.4>
   0x0000000008000994 <+26>:    callq  0x8000810 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
   0x0000000008000999 <+31>:    mov    %rax,%rdx
   0x000000000800099c <+34>:    mov    0x20162d(%rip),%rax        # 0x8201fd0
   0x00000000080009a3 <+41>:    mov    %rax,%rsi
   0x00000000080009a6 <+44>:    mov    %rdx,%rdi
   0x00000000080009a9 <+47>:    callq  0x8000820 <_ZNSolsEPFRSoS_E@plt>
   0x00000000080009ae <+52>:    nop
   0x00000000080009af <+53>:    leaveq
   0x00000000080009b0 <+54>:    retq
End of assembler dump.