下面的代码包含两个相同的lambda,但是用g++5编译时会产生不同的答案。在参数声明中使用auto关键字的lambda编译良好,但返回零而不是正确的计数1。为什么?我应该添加代码,用g++-6生成正确的输出。
g++-5 -std=c++14 file.cc
./a.out
Output:
f result=0 (incorrect result from lambda f)
...
g result=1 (correct result from lambda g)
...
#include<iostream>
#include<set>
#include<vector>
#include<algorithm>
using namespace std;
enum obsMode { Hbw, Lbw, Raw, Search, Fold};
int main(int , char **)
{
static set<obsMode> legal_obs_modes = {Hbw, Lbw, Raw, Search, Fold};
vector<obsMode> obs_mode = { Hbw,Lbw,Hbw,Lbw};
// I named the lambdas to illustrate the issue
auto f = [&] (auto i) -> void
{
cout << "f result=" << legal_obs_modes.count(i) << endl;
};
auto g = [&] (obsMode i) -> void
{
cout << "g result=" << legal_obs_modes.count(i) << endl;
};
// f does not work
for_each(obs_mode.begin(), obs_mode.end(), f);
// g does work
for_each(obs_mode.begin(), obs_mode.end(), g);
return 0;
}发布于 2020-08-11 04:44:53
深入研究这个问题,就可以看出问题是什么。
它似乎一直存在,从5.1到6.1 (根据编译器资源管理器),我注意到可能相关的这个定向修复6.2错误的报告。错误的代码是:
#include <iostream>
#include <functional>
int main() {
static int a;
std::function<void(int)> f = [](auto) { std::cout << a << '\n'; };
a = 1;
f(0);
}它打印的是0而不是正确的1。基本上,静力学和lambdas的使用引起了一些麻烦,因为在lambda创建时,一个静态变量被作为副本提供给lambda。对于这个特定的bug报告,它意味着静态变量似乎总是具有创建lambda时的值,而不管您在这段时间对它做了什么。
我最初认为这不可能相关,因为这个问题中的静态是在声明时初始化的,并且在lambda创建之后从未改变过。但是,如果您在创建lambda之前放置了以下行,并将其作为每个lambda中的第一行,并使用选项x86-64 6.1 --std=c++14编译(同样,在编译器资源管理器上)
cout << &legal_obs_modes << ' ' << legal_obs_modes.size() << '\n';然后,您将看到一些非常有趣的东西(我已经为可读性做了一些调整):
0x605220 5
0x605260 0 f result=0
0x605260 0 f result=0
0x605260 0 f result=0
0x605260 0 f result=0
0x605220 5 g result=1
0x605220 5 g result=1
0x605220 5 g result=1
0x605220 5 g result=1失败的f地址大小为零,而不是5,地址完全不同。零大小足够表明count将返回零,仅仅是因为空集中没有元素。我怀疑不同的地址是链接错误报告中涉及的相同问题的一种表现。
您实际上可以在Compiler Explorer汇编程序输出中看到这一点,其中两个不同的lambda加载一个不同的设置地址:
mov edi, 0x605260 ; for f
mov edi, 0x605220 ; for g使设定自动而非静态,使问题完全消失。地址在lambda内部和外部都是相同的,0x7ffd808eb050 (栈内而不是静态区域,因此值发生了很大的变化)。这往往与这样一个事实结合在一起:静力学实际上并不是在lambdas中捕捉到的,因为它们总是应该在同一个地址,所以可以按原样使用。
因此,问题似乎是,f lambda使用其auto-deduced参数正在复制静态数据,而不是在原地使用它。我不是指好的拷贝,我指的是类似于2017年某个时候用完墨粉的复印机:-)
因此,在回答你关于这是否是一个错误的具体问题时,我认为大家的共识是肯定的。
https://stackoverflow.com/questions/43837337
复制相似问题