c ++ 11 lambda是否捕获不使用的变量?


123

当我[=]用来表示我希望通过lambda中的值捕获所有局部变量时,这是否会导致函数中的所有局部变量被复制,或者仅仅是lambda使用的所有局部变量?

因此,例如,如果我有:

vector<int> my_huge_vector(100000);
int my_measly_int;
some_function([=](int i){ return my_measly_int + i; });

即使我不在lambda中使用my_huge_vector,它也会被复制吗?

Answers:


114

捕获列表中明确命名的每个变量均被捕获。默认捕获将仅捕获以下两个变量:(a)在捕获列表中未明确命名的变量和(b)在lambda表达式主体中使用的变量。如果未明确命名变量,并且您未在lambda表达式中使用该变量,则不会捕获该变量。在您的示例中,my_huge_vector未捕获。

根据C ++ 11§5.1.2[expr.prim.lambda] / 11:

如果λ-表达具有相关联捕捉默认及其化合物语句 ODR用途 this或具有自动存储持续时间和所述的可变ODR使用的实体没有明确地捕获,则ODR使用的实体被认为是隐式地捕获。

您的lambda表达式具有关联的捕获默认值:默认情况下,您使用值来捕获变量[=]

当且仅当使用了变量(在“一个定义规则”中,术语“已使用”的含义)是隐式捕获的变量。由于您根本不使用my_huge_vectorlambda表达式的主体(“复合语句”),因此不会隐式捕获它。

继续第5.1.2 / 14节

如果存在,则通过复制捕获实体

  • 它被隐式捕获,并且capture-default=
  • 使用不包含的捕获显式捕获它&

由于您my_huge_vector不会被隐式捕获,也不会被显式捕获,因此根本不会通过复制或引用来捕获您。


10
你有圣言吗?
GManNickG

不过,我会说,§5.1.2的整体对于理解所有细节很重要。在该部分中定义了许多技术术语,并且由于必定会纠缠lambda表达式的各个组成部分,因此很难引出明确表示“这是X,这就是X的原因”的短引号。
James McNellis 2011年

请注意此处的提示,该提示表示不允许这样的优化,至少对于显式命名的变量是不允许的。我不确定在哪里划界线。
GManNickG

@GManNickG:那是一些强大的拖钓;-)。在意识到该链接确实指向此页面之前,我花了三秒钟的时间才找到该链接...:-O [无论如何,明天早上我进入办公室时,我会重新阅读语言规范并进行更新正确答案。]
James McNellis 2012年

哦,废话,对不起!我的问题得到了回答,我打算在这里链接。那肯定令人困惑。
GManNickG 2012年

16

不,my_huge_vector不会被捕获。[=]表示所有使用的变量都在lambda中捕获。


6
是的 但是请注意,“ 使用”是一个专业用词,实际上意味着“ 使用一个定义规则” 。因此,例如,考虑void f() { const int size(10); [] { int x[size]; }; }。在这里,size不会被捕获,但是没关系,因为它不是在ODR的意义上使用的。(Visual C ++ 2010不接受此代码,可能是由于VC10发布后规范发生了变化,也可能是由于有错误导致的bug,可能这将在以后的版本中得到修复; g ++ 4.5.1接受了此代码。)
James McNellis

@JamesMcNellis dpn不必担心,MSVC今天仍然是一堆臭废话。cf. godbolt.org/z/vHnnCX(在gcc中检查lulz)。那说; 我不明白为什么未在评估表达式中出现的任何标识符都不能使用ODR。我认为这种情况肯定是ODR使用的,除非您的意思是可以将其解释为constexpr,因此只有该值有用吗?我不确定编译器是否假定某些const内容不会发生变异。除非超级激进的优化标志OX或其他东西。
v.oddou
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.