这是一个使用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
lang版本是:
$ clang++ --version
clang version 3.8.0 (tags/RELEASE_380/final)
我还尝试在Debian上使用GCC 4.9.2,在其中可执行文件可以产生正确的结果。
这可能是GCC中的错误,还是我做错了什么?任何人都可以重现吗?
编辑:我设法在Mac OS的GCC 6的Homebrew版本上也重现了该问题。
valarray
而且auto
不要混在一起。
这将创建一个临时对象,然后将operator/
其应用于:
const auto& res ( ratios_t::value_type(256) / a );
libstdc ++valarray
使用表达式模板,以便operator/
返回一个轻量级对象,该对象引用原始参数并懒惰地对其求值。使用const auto&
会导致表达式模板绑定到引用,但不会延长表达式模板所引用的临时项的生存期,因此,当评估发生时,该临时项已超出范围,并且其内存已被重用。
如果您这样做,它将正常工作:
ratios_t res = ratios_t::value_type(256) / a;
更新:从今天开始,GCC中继将提供此示例的预期结果。我已经修改了valarray
表达式模板,使它不太容易出错,因此创建悬挂引用比较困难(但并非没有可能)。明年,新的实施应包含在GCC 9中。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句