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

GCC incorrectly captures global variables by reference in lambda functions?

本文关键字:错误 全局变量 引用 lambda 函数 GCC      更新时间:2023-10-16

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可能会出于优化目的使用对该变量的引用,至少在这种情况下是这样,并且不会检测到错误的分配。

§5.1.2/11:

如果*lambda表达式(具有关联的捕获默认值,并且其复合语句odr使用(3.2)this具有自动存储持续时间的变量,并且odr使用的实体未显式捕获,则称odr使用实体为隐式捕获。。。

全局变量具有静态存储持续时间(§3.7.1),因此全局a不会被值隐式捕获。尽管如此,您可以在任何地方访问全局变量,因此

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

将如预期的那样将全局CCD_ 3设置为9。

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

捕获列表中的标识符使用非限定名称查找的常用规则进行查找(3.4.1.);每个这样的查找将找到在局部lambda表达式的到达范围中声明的具有自动存储持续时间的变量