为什么C ++中的lambda会包含所有引用?

时间:2019-06-07 11:17:20

标签: c++ optimization lambda x86 g++

使用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中包含所有引用?

1 个答案:

答案 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