使用g++.exe -m64 -std=c++17
和任何优化级别进行编译,然后运行:
#include <iostream>
int main() {
const auto L1 = [&](){};
std::cout << sizeof(L1) << std::endl;
const auto L2 = [&](){L1;};
std::cout << sizeof(L2) << std::endl;
const auto L3 = [&](){L1, L2;};
std::cout << sizeof(L3) << std::endl;
const auto L4 = [&](){L1, L2, L3;};
std::cout << sizeof(L4) << std::endl;
}
输出为1,8,16,24
,这意味着L2包含1个引用,L3包含2个引用,L4包含3个引用。
但是,给定相同的功能“ {{1}”中的“ [&](){L1, L2;}
”,main()
的值应固定,并使用&L1 - &L2
和指向{{1 }},假设L1
在x86 L2
中有直接寻址。为什么GCC仍然选择在lambda中包含所有引用?
答案 0 :(得分:1)
我认为这是一个错过的优化,因此您可以将其报告为https://gcc.gnu.org/bugzilla/上的gcc错误。使用missed-optimization关键字。
捕获lambda本身并不是一个函数,并且不能衰减/转换为函数指针,因此我认为lambda对象没有任何必需的布局。 (Use a lambda as a parameter for a C++ function)。读取lambda对象的生成代码将始终从定义该对象的同一编译单元生成。因此,所有本地人只需要一个基本指针,并以此偏移即可。
其他捕获类型不是自动的存储类的变量可能仍需要单独的指针,如果它们彼此之间的偏移量不是编译时常量或至少不是链接时常量。 (或者这可能是一个单独的优化。)
实际上,您可以通过将lambda传递给__attribute__((noinline))
模板函数来使编译器使用空间并在内存中创建lambda对象。 https://godbolt.org/z/Pt0SCC。