[英]Why can't C++ locals captured by reference be accessed through the stack pointer?
我注意到編譯器通過在指向捕獲的局部變量的指針堆棧上創建一個數組來實現引用捕獲,可以將其傳遞給 lambda 以訪問它們。 這讓我感到驚訝,因為編譯器知道本地變量相對於堆棧指針的位置,所以我認為它可以只傳遞堆棧指針。 這將減少 lambda 中的間接性並節省將指針放入堆棧的工作。 我想知道為什么編譯器不能這樣做?
例如,這個 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 上類似。
您看到的不是未優化的 lambda,而是
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);
}
我添加了testABI<\/code>以顯示您的函數的參數是由注冊表傳遞的。
<\/li><\/ol>
因此,在test2<\/code>中,首先創建x<\/code>和y<\/code>以在堆棧上創建局部變量,因此可以通過引用傳遞它們。
<\/li>
在堆棧上創建 lambda 之后,將x<\/code>和y<\/code>的地址保存到堆棧中。
使用 lambda 時要調用的函數的地址(沒有 vtable 的多態性)也被添加到堆棧上的 labda<\/li><\/ol> 現在你不知道test<\/code>會對f<\/code>做什么。
它可以克隆f<\/code>所以在這種情況下f<\/code>必須從堆棧復制到其他地方。
另一方面,編譯test<\/code>時編譯器不知道通過了哪種 lambda。
創建副本可能有副作用,也可能沒有。 因此,必須可以創建副本並且必須與預定義的 ABI 兼容。
因此,只有當編譯器可以知道
test<\/code>的內容時,您所描述的這種快捷方式才有可能。
當不知道
test<\/code>內容時,必須完全創建
f<\/code>才能在需要時克隆它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.