我注意到编译器通过在堆栈上创建指向捕获本地变量的指针数组来实现引用捕获,可以将其传递给 lambda 表达式进行访问。这使我感到惊讶,因为编译器知道本地变量相对于堆栈指针的位置,所以我认为它可以直接传递堆栈指针。这样可以减少 lambda 表达式中的一次间接访问,并节省将指针放入堆栈的工作。我想知道为什么编译器不能那样做。
例如,这段 C++ 代码:
在GCC和MSVC上也类似。
例如,这段 C++ 代码:
#include <functional>
extern void test(std::function<void()>& f);
int test2(int x, int y)
{
std::function<void()> f([&]() { x += y; });
test(f);
return x;
}
在Clang 13 -O3下生成此汇编(注释为我的解释):
mov dword ptr [rsp + 8], edi // put x on the stack
mov dword ptr [rsp + 12], esi // put y on the stack
lea rax, [rsp + 8]
mov qword ptr [rsp + 16], rax // put &x on the stack
lea rax, [rsp + 12]
mov qword ptr [rsp + 24], rax // put &y on the stack
mov qword ptr [rsp + 40], offset std::_Function_handler<void (), test2(int, int)::$_0>::_M_invoke(std::_Any_data const&)
mov qword ptr [rsp + 32], offset std::_Function_handler<void (), test2(int, int)::$_0>::_M_manager(std::_Any_data&, std::_Any_data const&, std::_Manager_operation)
lea rdi, [rsp + 16]
call test(std::function<void ()>&)
在GCC和MSVC上也类似。
std::function
并不是一个 lambda 表达式,它相当复杂且难以优化。如果你只使用 lambda 表达式,编译器可能会消除所有这些代码。 - Mat