c++11 lambdas 捕获他们不使用的变量吗?
Posted
技术标签:
【中文标题】c++11 lambdas 捕获他们不使用的变量吗?【英文标题】:Do c++11 lambdas capture variables they don't use? 【发布时间】:2011-09-05 02:31:14 【问题描述】:当我使用[=]
表示我希望通过 lambda 中的值捕获所有局部变量时,这会导致函数中的 all 局部变量被复制,还是全部复制lambda 使用的局部变量?
所以,例如,如果我有:
vector<int> my_huge_vector(100000);
int my_measly_int;
some_function([=](int i) return my_measly_int + i; );
是否会复制 my_huge_vector,即使我不在 lambda 中使用它?
【问题讨论】:
【参考方案1】:捕获列表中明确命名的每个变量都会被捕获。默认捕获将仅捕获 (a) 未在捕获列表中明确命名的变量和 (b) used 在 lambda 表达式的主体中的变量。如果变量没有明确命名,并且您没有在 lambda 表达式中使用该变量,则不会捕获该变量。在您的示例中,my_huge_vector
未被捕获。
根据 C++11 §5.1.2[expr.prim.lambda]/11:
如果一个 lambda-expression 有一个关联的 capture-default 及其 compound-statement odr-uses
this
或具有自动存储持续时间的变量,并且 odr-used 实体没有被显式捕获,则 odr-used 实体被称为隐式捕获。 p>
您的 lambda 表达式具有关联的默认捕获:默认情况下,您使用 [=]
按值捕获变量。
当且仅当使用了变量(在“使用”一词的单一定义规则意义上)是隐式捕获的变量。由于您根本没有在 lambda 表达式的主体(“复合语句”)中使用 my_huge_vector
,因此它不会被隐式捕获。
继续 §5.1.2/14
一个实体被副本捕获如果
它是隐式捕获的,capture-default 是=
或如果 它是通过不包含&
的捕获显式捕获的。
由于您的 my_huge_vector
没有被隐式捕获,也没有被显式捕获,因此根本不会通过复制或引用来捕获它。
【讨论】:
你有圣言吗? 不过,我要说的是,第 5.1.2 节的全部内容对于理解所有细节很重要。该部分定义了许多技术术语,并且由于 lambda 表达式的各个组成部分的定义必然纠缠在一起,因此很难抽出短引号来明确地说“这是 X,这就是 X 的原因”。跨度> 提醒您注意here,它表示不允许这样的优化,至少对于显式命名的变量是这样。我不知道在哪里画线。 @GManNickG:这是一些非常好的拖钓;-)。在我意识到它确实指向这个页面之前,我花了三下点击该链接...... :-O [无论如何,我明天早上进入办公室时会重新阅读语言规范并更新适当的答案。] 哦,废话,对不起!!!我的问题得到了回答,我的意思是链接here。那一定是非常令人困惑的。【参考方案2】:不,my_huge_vector
不会被捕获。 [=]
表示所有使用的变量都被捕获在 lambda 中。
【讨论】:
是的。请注意,used 是一个技术词,实际上表示单一定义规则 used。因此,例如,考虑void f() const int size(10); [] int x[size]; ;
。在这里,size
没有被捕获,但这没关系,因为它没有在 ODR 意义上使用。 (Visual C++ 2010 不接受这个代码,要么是因为 VC10 发布后规范发生了变化,要么是由于一个 bug,估计这将在即将发布的版本中修复;g++ 4.5.1 接受它。)
@JamesMcNellis dpn 别担心,MSVC 今天仍然是一堆臭屁。参看。 godbolt.org/z/vHnnCX(在 gcc 中查看 lulz)。那就是说;我不明白为什么出现在评估表达式中的任何标识符都不会被 ODR 使用。我认为这种情况肯定是 ODR 使用的,除非你的意思是它可以被解释为 constexpr 因此只有值是有用的?我不确定编译器是否假定 const
的东西不会发生变异。除非可能是超级激进的优化标志 OX 或其他东西。以上是关于c++11 lambdas 捕获他们不使用的变量吗?的主要内容,如果未能解决你的问题,请参考以下文章
C ++ 11 lambda捕获`this`并按值捕获局部变量