I noticed that compilers implement capture by reference by making an array on the stack of pointers to the captured locals, which can be passed to the lambda to access them. That surprised me because the compiler knows where the locals are relative to the stack pointer, so I thought it could just pass the stack pointer. That would make one less indirection in the lambda and save the work of putting the pointers on the stack. I was wondering why the compiler can't do that?
For example, this 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;
}
generates this assembly on Clang 13 -O3 (comments mine):
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 ()>&)
and similar on GCC and MSVC.
What you see is not the non optimized lambda, but all the stuff around std::function<\/code> .
template < typename F>
void test(F& f )
{
f();
}
int test2(int x, int y)
{
auto f=[&]() { x += y; };
test(f);
return x;
}
int main()
{
return test2(1,2);
}
<\/li><\/ol>
<\/li>
Also addresses of functions to be invoked when lambda is used (polymorphism without vtable) are added to labda on stack<\/li><\/ol> Now you do not know what test<\/code> will do with f<\/code> .
It can clone f<\/code> so in such case f<\/code> have to be copied from stack to other place.
Also on other side when test<\/code> is compiled compiler do not know what kind of lambda was passed.
Creating copy may have side effect or not. So creating a copy must be possible and must be compatible with predefined ABI.
When content of
test<\/code> is not know
f<\/code> must be fully created to make it possible to clone it when needed.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.