我有以下初始C ++代码:
class Lambda
{
public:
int compute(int &value){
auto get = [&value]() -> int {
return 11 * value;
};
return get();
}
};
int main(){
Lambda lambda;
int value = 77;
return lambda.compute(value);
}
使用clang编译(使用-O1)的在ASM下生成:
main: # @main
push rax
mov dword ptr [rsp + 4], 77
mov rdi, rsp
lea rsi, [rsp + 4]
call Lambda::compute(int&)
pop rcx
ret
Lambda::compute(int&): # @Lambda::compute(int&)
push rax
mov qword ptr [rsp], rsi
mov rdi, rsp
call Lambda::compute(int&)::{lambda()#1}::operator()() const
pop rcx
ret
Lambda::compute(int&)::{lambda()#1}::operator()() const: # @Lambda::compute(int&)::{lambda()#1}::operator()() const
mov rax, qword ptr [rdi]
mov eax, dword ptr [rax]
lea ecx, [rax + 4*rax]
lea eax, [rax + 2*rcx]
ret
问题:
{lambda()#1}
是什么?据我所知,它可能是一个封装函数对象(即lambda体)的闭包。
请确认是否。compute()
时都会生成新的闭包吗?或者是同一个实例?答案 0 :(得分:2)
compute
中声明的lambda函数的主体(实现)。 rdi
传递,即作为第一个参数,与成员函数指向的this
相同)。 1 "在此优化级别"部分非常重要。这里没有任何东西实际上需要编译器生成闭包或单独的lambda函数。例如,在-O2
,clang optimizes all this away只会直接在main()
中将答案作为常量返回。即使在-O1
,gcc也会执行相同的优化。
答案 1 :(得分:2)
通过此优化,每次调用都会调用compute
,后者又会调用内部函数get()
,这是compute
函数中的lambda函数。让编译器进行更高程度的优化,对于这种情况,将优化呼叫 - 在我的尝试中,它将完全删除整个呼叫-O2
,并且只返回预先计算的常数847 - 就像你和期待。对于更复杂的情况,它可能会或可能不会内联lambda部分但保持外部调用,反之亦然。这在很大程度上取决于所涉及功能内部的具体细节。
为了清楚起见,编译器完全按照您的要求执行操作:调用函数compute
,然后调用函数get
。
添加
int value2 = 88;
int tmp = lambda.compute(value2);
进入原始问题中的main
函数基本上会对生成的代码产生这种更改(在Linux上使用clang ++):
main: # @main
pushq %rbx
subq $16, %rsp
movl $77, 12(%rsp)
## new line to set value2
movl $88, 8(%rsp)
movq %rsp, %rbx
## New line, passing reference of `value2` to lambda.compute
leaq 8(%rsp), %rsi
movq %rbx, %rdi
## Call lambda.compute
callq _ZN6Lambda7computeERi
## Same as before.
leaq 12(%rsp), %rsi
movq %rbx, %rdi
callq _ZN6Lambda7computeERi
addq $16, %rsp
popq %rbx
retq
生成的代码