调整优化等级后std::valarray求和结果不一致的原因排查
std::valarray求和在GCC高优化等级下结果异常的原因
问题描述
我编写了一段对std::valarray<int>进行求和的代码:
#include <iostream> #include <valarray> #include <vector> int main() { std::vector<std::valarray<int>> vectorOfValarrays{{1, 1}, {2, 2}, {3, 3}}; std::valarray<int> sumOfValarrays(2); for (const auto& i : vectorOfValarrays) sumOfValarrays = sumOfValarrays + i; std::cout << sumOfValarrays[0] << ' ' << sumOfValarrays[1]; }
使用x86-64 GCC 12.2编译器,在-O0和-O1优化等级下编译运行,输出预期结果6 6;但在-O2和-O3优化等级下,输出结果变为3 3。请问这是什么原因?是代码存在未定义行为还是GCC的bug?
原因分析与解决方案
这是代码触发未定义行为导致的问题,并非GCC的bug。
问题出在sumOfValarrays = sumOfValarrays + i;这一行:
sumOfValarrays + i会生成一个临时std::valarray<int>对象,存储求和后的结果- 在高优化等级下,GCC的激进优化可能会将临时对象的计算直接复用
sumOfValarrays的内存空间,导致原对象的元素在赋值完成前就被覆盖。后续元素的计算会使用被覆盖后的值,最终得到错误的结果。
而std::valarray的operator+=是专门为原地更新设计的,它会直接在原对象的内存上完成求和操作,不会产生临时对象与原对象内存重叠的风险。
修复代码
将赋值语句替换为operator+=即可解决问题:
#include <iostream> #include <valarray> #include <vector> int main() { std::vector<std::valarray<int>> vectorOfValarrays{{1, 1}, {2, 2}, {3, 3}}; std::valarray<int> sumOfValarrays(2); for (const auto& i : vectorOfValarrays) sumOfValarrays += i; std::cout << sumOfValarrays[0] << ' ' << sumOfValarrays[1]; }
无论使用哪个优化等级,这段代码都会输出正确的6 6。
内容的提问来源于stack exchange,提问作者justANewb stands with Ukraine
相关产品推荐
相关产品推荐

