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

use*_*938 13 c++ lambda gcc c++11

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

#include <iostream>

int a = 10;

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

虽然这段代码不会编译:

#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;
}
Run Code Online (Sandbox Code Playgroud)

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

#include <iostream>

int a = 10;

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

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

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

ken*_*ytm 24

§5.1.2/ 11:

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

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

[=]() { a = 9; } ();
Run Code Online (Sandbox Code Playgroud)

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

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

标识捕获列表中查找使用不合格的名称查找的一般规则(3.4.1); 每个这样的查找应该找到一个变量,其自动存储持续时间在本地lambda表达式的到达范围内声明.