【问题标题】:Lambda in for loop - static variablefor循环中的Lambda - 静态变量
【发布时间】:2021-02-24 08:48:30
【问题描述】:

亲爱的 stackoverflow 社区!

最近,我正在寻找工作中的一个错误,这导致我找到了以下我自己编写的代码。这是一个简化的版本:

int main()
{
    for(int i = 0; i < 5; ++i)
    {
        int j = i + 1;

        auto k = [j](){
            static int s{j};
            cout << s << endl;
        };
        k();
    }
}

我知道它可能看起来很傻,但它背后有一些逻辑(因为我使用这个 lambda 连接到 QT 框架中的插槽)

这是我的期望:

  1. 将创建带有仿函数运算符的循环新类的每次迭代(因为每次它捕获新的局部变量时)
  2. 静态变量 s 的初始化将在每次迭代时发生一次,因为它是不同的 lambda

但是,我错了。使用 GCC 9.3.0 编译后,我得到以下输出:

1
1
1
1
1

这是否意味着每次循环迭代都会创建一个“隐藏”函子(然后在循环的第一次迭代期间初始化一个静态函数)?那么这是否意味着我们应该避免在 lambdas 中使用讨厌的非 constexpr 静态变量?我哪里错了?

感谢您的宝贵时间,期待任何回复。

【问题讨论】:

    标签: c++ c++11 lambda


    【解决方案1】:

    将 lambda 表达式视为定义重载调用 operator() 的类的简洁配方。在你的情况下:

    struct LambdaEquivalent {
        int j;
    
        auto operator() const
        {
            static int s{j};
            cout << s << endl;
        }
    };
    

    然后你循环是

    for(int i = 0; i < 5; ++i)
    {
            int j = i + 1;
            LambdaEquivalent k{j};
            k()
    }
    

    这说明 lambda 表达式主体中的任何本地静态数据只不过是成员函数中的本地静态数据 - 并且仅被初始化一次。两种情况的行为相同是一件好事,但以不同的方式处理可能会非常混乱。

    【讨论】:

    • 啊哈,现在我明白了,谢谢。我猜它只是归结为一个静态函数成员,它在第一次调用期间根据函数参数的值进行初始化。
    • cppinsights.io 可以帮助您将很多功能转换回 C++98 代码,并且可以生成这种洞察力
    猜你喜欢
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 2015-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多