繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM