GCC错误地通过lambda函数中的引用捕获全局变量?

时间:2012-02-08 19:02:30

标签: c++ gcc lambda c++11

GCC似乎错误地通过lambda函数中的引用捕获全局变量,即使它们被指定为'按值捕获'。此代码将编译并打印" a = 9":

#include <iostream>

int a = 10;

int main()
{
    [=]() { a = 9; } ();
    std::cout << "a = " << a << std::endl;
    return 0;
}

虽然此代码无法编译:

#include <iostream>

int main()
{
    int a = 10;
    [=]() { a = 9; } (); // error: assignment of member 'main()::<lambda()>::a' in read-only object
    std::cout << "a = " << a << std::endl;
    return 0;
}

但显式捕获全局值然后分配给它会产生错误:

#include <iostream>

int a = 10;

int main()
{
    [a]() { a = 9; } (); // assigment of read-only object
    std::cout << "a = " << a << std::endl;
    return 0;
}

我非常确定错误是正确的行为 - 为什么隐式捕获会绕过这个错误?我正在探索新的C ++ 11功能,并意外地编​​写了第一段代码(没有意识到它应该是一个错误),然后当我假设的局部变量的修改影响了全局时,我感到很惊讶。

由于分配给lambda中的值捕获变量应该是一个错误,因此GCC可能会使用对变量的引用进行优化,至少在这种情况下,并不会检测到错误分配

1 个答案:

答案 0 :(得分:24)

§5.1.2/ 11:

  

如果* lambda表达式(具有关联的 capture-default 及其复合语句 odr-uses(3.2)this具有自动存储持续时间的变量并且未显式捕获使用了odr的实体,然后使用odr使用的实体隐式捕获; ...

全局变量具有静态存储持续时间(第3.7.1节),因此全局a不会被值隐式捕获。不过,你可以在任何地方访问全局变量,所以

[=]() { a = 9; } ();

会按预期将全局a设置为9.

明确捕获全局应该是错误或UB,因为§5.1.2/ 10说

  

使用通常的非限定名称查找规则(3.4.1)查找捕获列表中的标识符;每个这样的查找都应该找到在本地lambda表达式的到达范围内声明的具有自动存储持续时间的变量