为什么GCC优化不适用于valarrays?

DoD*_*oDo 11 c++ gcc g++ clang++

这是一个使用valarrays的简单c ++程序:

#include <iostream>
#include <valarray>

int main() {
    using ratios_t = std::valarray<float>;

    ratios_t a{0.5, 1, 2};
    const auto& res ( ratios_t::value_type(256) / a );
    for(const auto& r : ratios_t{res})
        std::cout << r << " " << std::endl;
    return 0;  
}
Run Code Online (Sandbox Code Playgroud)

如果我编译并运行它像这样:

g++ -O0 main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)

输出如预期:

512 256 128 
Run Code Online (Sandbox Code Playgroud)

但是,如果我编译并运行它:

g++ -O3 main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)

输出是:

0 0 0 
Run Code Online (Sandbox Code Playgroud)

如果我使用-O1优化参数,也会发生相同

GCC版本是(最新的Archlinux):

$ g++ --version
g++ (GCC) 6.1.1 20160707
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试使用clang,两者都可以

clang++ -std=gnu++14 -O0 main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)

clang++ -std=gnu++14 -O3 main.cpp && ./a.out
Run Code Online (Sandbox Code Playgroud)

产生相同的正确结果:

512 256 128 
Run Code Online (Sandbox Code Playgroud)

Clang版本是:

$ clang++ --version
clang version 3.8.0 (tags/RELEASE_380/final)
Run Code Online (Sandbox Code Playgroud)

我也尝试过在Debian上使用GCC 4.9.2,其中可执行文件产生正确的结果.

这是GCC中可能存在的错误还是我做错了什么?任何人都可以重现这个吗?

编辑:我设法在Mac OS上的Homebrew版本的GCC 6上重现了这个问题.

Jon*_*ely 6

valarray并且auto不要混合好.

这会创建一个临时对象,然后应用于operator/它:

const auto& res ( ratios_t::value_type(256) / a );
Run Code Online (Sandbox Code Playgroud)

libstdc ++ valarray使用表达式模板,以便operator/返回一个轻量级对象,该对象引用原始参数并懒惰地评估它们.您使用const auto&哪个导致表达式模板绑定到引用,但不延长表达式模板引用的临时表的生命周期,因此当评估发生时,临时表已超出范围,并且其内存已被重用.

如果您这样做,它将正常工作:

ratios_t res = ratios_t::value_type(256) / a;
Run Code Online (Sandbox Code Playgroud)

更新:截至今天,GCC主干将为此示例提供预期结果.我已经修改了我们的valarray表达式模板,使其更容易出错,因此创建悬空引用更难(但仍然不是不可能).新的实施应该包括在明年的GCC 9中.