[英]Auto in lambda bug in g++-5?
以下代码包含两个相同的 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;
}
深入研究这个问题就会发现问题是什么。
它似乎从 5.1 到 6.1 一直存在(根据Compiler Explorer ),我注意到这个可能相关的针对 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
。 基本上,静态变量和 lambda 的使用引起了一些麻烦,因为在创建 lambda 时,静态变量作为副本可供 lambda 使用。 对于那个特定的错误报告,这意味着静态变量似乎总是具有创建 lambda 时所具有的值,无论您在此期间对它做了什么。
我最初认为这不可能相关,因为这个问题中的静态是在声明时初始化的,并且在 lambda 创建后从未改变。 但是,如果您在创建 lambdas 之前放置以下行并将其作为每个 lambda 中的第一行,并使用选项--std=c++14
使用x86-64 6.1
编译(再次在编译器资源管理器上):
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
个的大小为 0 而不是 5,并且地址完全不同。 零大小足以表明count
将返回零,仅仅是因为空集中没有元素。 我怀疑不同的地址是链接错误报告中涵盖的相同问题的表现。
您实际上可以在Compiler Explorer
汇编器输出中看到这一点,其中两个不同的 lambda 加载了不同的设置地址:
mov edi, 0x605260 ; for f
mov edi, 0x605220 ; for g
使设置自动而不是静态会导致问题完全消失。 地址在 lambda 内部和外部都相同, 0x7ffd808eb050
(堆栈上而不是静态区域,因此值发生了巨大变化)。 这往往与静态实际上并未在 lambda 中捕获的事实相结合,因为它们总是应该位于相同的地址,因此可以按原样使用。
因此,问题似乎在于f
lambda 及其auto
推导的参数正在制作静态数据的副本,而不是原位使用它。 我的意思不是好的副本,我的意思是类似于 2017 年某个时候碳粉用完的复印机:-)
因此,在回答您关于这是否是错误的具体问题时,我认为共识将是相当强调是的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.