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

标签 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;  
}

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

g++ -O0 main.cpp && ./a.out

输出符合预期:

512 256 128 

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

g++ -O3 main.cpp && ./a.out

输出是:

0 0 0 

如果我使用 -O1 优化参数,也会发生同样的情况。

GCC 版本是(Archlinux 中的最新版本):

$ g++ --version
g++ (GCC) 6.1.1 20160707

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

clang++ -std=gnu++14 -O0 main.cpp && ./a.out

clang++ -std=gnu++14 -O3 main.cpp && ./a.out

产生相同的正确结果:

512 256 128 

Clang 版本是:

$ clang++ --version
clang version 3.8.0 (tags/RELEASE_380/final)

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

这可能是 GCC 中的错误还是我做错了什么?任何人都可以复制这个吗?

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

最佳答案

valarrayauto 不能很好地混合。

这将创建一个临时对象,然后对其应用 operator/:

const auto& res ( ratios_t::value_type(256) / a );

libstdc++ valarray 使用表达式模板,以便 operator/ 返回一个轻量级对象,该对象引用原始参数并延迟计算它们。您使用 const auto& 导致表达式模板绑定(bind)到引用,但不会延长表达式模板引用的临时对象的生命周期,因此当评估发生时,临时对象已经消失范围,其内存已被重用。

如果你这样做,它会工作得很好:

ratios_t res = ratios_t::value_type(256) / a;

更新:截至今天,GCC trunk 将给出此示例的预期结果。我修改了我们的 valarray 表达式模板,使其不易出错,这样就更难(但并非不可能)创建悬空引用。新的实现应该包含在明年的 GCC 9 中。

关于c++ - 为什么 GCC 优化不适用于 valarrays?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38354521/

相关文章:

c++ - 使用类型转换在 C++ 中返回二维数组

c++ - 使用 pthreads 作为类成员的互斥体

gcc - 向量按位且在GCC上具有恒定值

c++ - 使 cpp(C 预处理器)删除 Mac OS X 上的 C++ 注释

c++ - 为什么这个imapclient g++编译会出错

c++ - imread 命令后 OpenCV 矩阵内存释放

c++ - 如何让 g++ 拒绝任何表现出未定义行为的代码?

c++ - OpenCV accumulatedWeight 错误( channel 和大小比较断言失败)

c++ - 无法将 LIBEVENT 链接为 C++

c++ - 如何在 C++ 中创建带有引用成员的数组?