首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在g++-5中自动进入λ错误吗?

在g++-5中自动进入λ错误吗?
EN

Stack Overflow用户
提问于 2017-05-07 12:18:04
回答 1查看 82关注 0票数 3

下面的代码包含两个相同的lambda,但是用g++5编译时会产生不同的答案。在参数声明中使用auto关键字的lambda编译良好,但返回零而不是正确的计数1。为什么?我应该添加代码,用g++-6生成正确的输出。

代码语言:javascript
复制
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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-11 04:44:53

深入研究这个问题,就可以看出问题是什么。

它似乎一直存在,从5.1到6.1 (根据编译器资源管理器),我注意到可能相关的这个定向修复6.2错误的报告。错误的代码是:

代码语言:javascript
复制
#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编译(同样,在编译器资源管理器上)

代码语言:javascript
复制
cout << &legal_obs_modes << ' ' << legal_obs_modes.size() << '\n';

然后,您将看到一些非常有趣的东西(我已经为可读性做了一些调整):

代码语言:javascript
复制
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加载一个不同的设置地址:

代码语言:javascript
复制
mov    edi, 0x605260 ; for f
mov    edi, 0x605220 ; for g

使设定自动而非静态,使问题完全消失。地址在lambda内部和外部都是相同的,0x7ffd808eb050 (栈内而不是静态区域,因此值发生了很大的变化)。这往往与这样一个事实结合在一起:静力学实际上并不是在lambdas中捕捉到的,因为它们总是应该在同一个地址,所以可以按原样使用。

因此,问题似乎是,f lambda使用其auto-deduced参数正在复制静态数据,而不是在原地使用它。我不是指好的拷贝,我指的是类似于2017年某个时候用完墨粉的复印机:-)

因此,在回答你关于这是否是一个错误的具体问题时,我认为大家的共识是肯定的。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43837337

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档