gpt4 book ai didi

c++ - g++-5 中的 lambda 错误中的自动?

转载 作者:行者123 更新时间:2023-12-01 14:18:51 24 4
gpt4 key购买 nike

以下代码包含两个相同的 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 ),我注意到 this targeted-for-fix-in-6.2 bug report这可能是相关的。错误的代码是:

#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 创建后从未改变。但是,如果您在创建 lambda 之前放置以下行并将其作为每个 lambda 中的第一行,并使用带有选项 --std 的 x86-64 6.1 进行编译(同样,在 Compiler Explorer 上) =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 的大小为零而不是五个,并且地址完全不同。零大小足以表明 count 将返回零,这仅仅是因为空集中没有元素。我怀疑不同的地址是所涵盖的同一问题的表现在链接的错误报告中。

您实际上可以在 Compiler Explorer 汇编器输出中看到这一点,其中两个不同的 lambda 加载了一个不同集合地址:

mov    edi, 0x605260 ; for f
mov edi, 0x605220 ; for g

使设置自动而不是静态会导致问题完全消失。地址在 lambdas 和它们之外的 中是相同的,0x7ffd808eb050(在堆栈上而不是在静态区域,因此值发生了巨大变化)。这往往与静态变量实际上并未在 lambda 表达式中捕获这一事实有关,因为它们总是应该位于同一地址,因此可以按原样使用。

因此,问题似乎是 f lambda 及其 auto 推导出的参数正在制作静态的拷贝数据而不是就地使用它。我的意思不是好的拷贝,我的意思是类似于 2017 年某个时候碳粉用完的复印机 :-)

因此,在回答您关于这是否是一个错误的具体问题时,我认为共识将是相当强调是的。

关于c++ - g++-5 中的 lambda 错误中的自动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43837337/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com