gpt4 book ai didi

c++ - C++ 标准是否强制局部变量的引用捕获效率低下?

转载 作者:可可西里 更新时间:2023-11-01 15:22:57 26 4
gpt4 key购买 nike

<分区>

我最近需要一个通过引用捕获多个局部变量的 lambda,所以我做了一个测试片段来研究它的效率,并使用 clang 3.6 用 -O3 编译它:

void do_something_with(void*);

void test()
{
int a = 0, b = 0, c = 0;

auto func = [&] () {
a++;
b++;
c++;
};

do_something_with((void*)&func);
}

movl   $0x0,0x24(%rsp)
movl $0x0,0x20(%rsp)
movl $0x0,0x1c(%rsp)

lea 0x24(%rsp),%rax
mov %rax,(%rsp)
lea 0x20(%rsp),%rax
mov %rax,0x8(%rsp)
lea 0x1c(%rsp),%rax
mov %rax,0x10(%rsp)

lea (%rsp),%rdi
callq ...

很明显,lambda 只需要其中一个变量的地址,所有其他变量都可以通过相对寻址从中获得。

相反,编译器在堆栈上创建了一个包含指向每个 局部变量的指针的结构,然后将结构的地址传递给 lambda。这和我写的差不多:

int a = 0, b = 0, c = 0;

struct X
{
int *pa, *pb, *pc;
};

X x = {&a, &b, &c};

auto func = [p = &x] () {
(*p->pa)++;
(*p->pb)++;
(*p->pc)++;
};

由于各种原因,这是低效的,但最令人担忧的是,如果捕获了太多变量,它可能会导致堆分配。

我的问题:

  1. 事实上,clang 和 gcc 在 -O3 中都这样做,这让我怀疑标准中的某些内容实际上强制闭包的实现效率低下。是这样吗?

  2. 如果是这样,那是出于什么原因?它不能用于编译器之间 lambda 的二进制兼容性,因为任何知道 lambda 类型的代码都保证位于同一翻译单元中。

  3. 如果不是,那么为什么两个主要编译器都缺少此优化?


编辑:
这是我希望从编译器中看到的更高效代码的示例。这段代码使用更少的堆栈空间,lambda 现在只执行一个指针间接寻址而不是两个,并且 lambda 的大小不会随着捕获变量的数量增加:

struct X
{
int a = 0, b = 0, c = 0;
} x;

auto func = [&x] () {
x.a++;
x.b++;
x.c++;
};

movl   $0x0,0x8(%rsp)
movl $0x0,0xc(%rsp)
movl $0x0,0x10(%rsp)

lea 0x8(%rsp),%rax
mov %rax,(%rsp)

lea (%rsp),%rdi
callq ...

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com