61

当我用 编写 lambda 时[=],这是否意味着我的所有局部变量都将被复制到创建的结构的成员中,还是我可以假设只有那些在 lambda 中实际使用的变量?例如:

void f()
{
    vector<int> v(10000);
    const int n = 5;
    const int DivByNCnt = count_if(istream_iterator<int>(cin), istream_iterator<int>(), 
          [=](int i)
          {
             return i % n == 0;
          });
}

以下哪项(如果有)是正确的?

  • n 和 v 都将被复制
  • n 将被复制,v 不会
  • n 将被复制,v 可能会或可能不会被复制,具体取决于实施/优化设置。

为了参数的缘故,假设 vector 的复制构造函数有副作用。

4

2 回答 2

63

不,这只是意味着环境范围内的所有局部变量都可用于在 lambda 的主体内查找。仅您引用环境局部变量的名称时,该变量才会被捕获,并且将按值捕获。

“捕获任何东西”的简写=&本质上只是语法糖,告诉编译器“弄清楚我的意思”。


来自 5.1.2/11-12 的正式参考:

如果 lambda 表达式具有关联的捕获默认值,并且其复合语句odr-uses [...] 具有自动存储持续时间的变量,并且未显式捕获使用 odr 的实体,则称使用 odr 的实体被隐含地捕获[...]

如果实体被显式或隐式捕获,则该实体被捕获。

请注意,“ capture-default ”指的是[=][&]。重复一遍,指定捕获默认值不会捕获任何内容;只有使用变量的 odr 才可以。

于 2013-03-25T10:22:40.767 回答
22

不!(谢天谢地)

你可以检测你的代码来检查你的编译器是否真的做到了(或没有)。例如gcc 4.8.0似乎是合规的。


至于标准的实际要求(向后工作):

§5.1.2/14 如果实体被式捕获并且默认捕获是,=或者如果使用不包含&. 对于复制捕获的每个实体,在闭包类型中声明了一个未命名的非静态数据成员。

$5.1.2/11 如果 lambda 表达式具有关联的捕获默认值及其复合语句 odr-uses (3.2)this或具有自动存储持续时间的变量,并且未显式捕获 odr-used 实体,则 odr-used实体被认为是隐式捕获的;此类实体应在 lambda 表达式的到达范围内声明。

§5.1.2/9 最小封闭范围是块范围 (3.3.3) 的 lambda 表达式是本地 lambda 表达式;任何其他 lambda-expression 在其 lambda-introducer 中都不应有捕获列表。本地 lambda 表达式的到达范围是一组封闭范围,直到并包括最内层的封闭函数及其参数。[注意:这个到达范围包括任何介入的 lambda 表达式。——尾注]

于 2013-03-25T10:26:15.777 回答