亲爱的 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();
}
}
Run Code Online (Sandbox Code Playgroud)
我知道它可能看起来很傻,但它背后有一些逻辑(因为我使用这个 lambda 连接到 QT 框架中的插槽)
以下是我的期望:
然而,我错了。使用 GCC 9.3.0 编译后,我得到以下输出:
1
1
1
1
1
Run Code Online (Sandbox Code Playgroud)
这是否意味着为循环的每次迭代创建一次“隐藏”函子(然后在循环的第一次迭代期间初始化静态)?那么这是否意味着我们应该避免在 lambdas 中使用讨厌的非 constexpr 静态变量?我哪里错了?
感谢您的时间,期待任何回复。
将 lambda 表达式视为定义重载调用的类的简洁方法operator()。在你的情况下:
struct LambdaEquivalent {
int j;
auto operator() const
{
static int s{j};
cout << s << endl;
}
};
Run Code Online (Sandbox Code Playgroud)
然后你循环是
for(int i = 0; i < 5; ++i)
{
int j = i + 1;
LambdaEquivalent k{j};
k()
}
Run Code Online (Sandbox Code Playgroud)
这说明 lambda 表达式主体中的任何本地静态数据只不过是成员函数中的本地静态数据 - 并且只初始化一次。两种情况的行为相同是一件好事,以不同的方式处理它可能会非常混乱。