为什么编译器优化会破坏我的代码?
我在使用此代码时遇到了一些问题。它在调试模式下工作,但在发布模式下会错误地为某些 csv 行输出 0.0。只有当我在第 19 行附近添加关闭优化的预处理器命令时,一切才开始在发布模式下工作。有没有人知道为什么会这样,我以前从未遇到过这种行为。
#include <vector>
#include <complex>
#include <fstream>
size_t constexpr kBins = 64;
double constexpr kFrequency = 16.0;
double Triangle(double const bin)
{
return abs(bin - floor(bin + 1.0 / 2.0));
}
int main()
{
std::vector<std::complex<double>> input{kBins, {0.0, 0.0}};
for (size_t i = 0; i < kBins; ++i)
{
#pragma optimize("" off)
double value = sin(2.0 * M_PI * kFrequency * Triangle(static_cast<double>(i) / kBins)) / (2.0 * M_PI * kFrequency * Triangle(static_cast<double>(i) / kBins));
#pragma optimize("" on)
input[i] = fpclassify(value) == FP_NAN ? 1.0 : value;
}
std::ofstream output_file{"output.csv"};
if (output_file.is_open())
{
for (size_t i = 0; i < kBins; ++i)
{
output_file << (static_cast<double>(i) / kBins) << ", " << input[i].real() << ", " << input[i].imag() << std::endl;
}
output_file.close();
}
}
回答
您的input向量没有按照您的预期进行初始化。它总是大小为 2,并且您观察到的所有奇怪结果都是由于读取向量越界而导致的未定义行为的结果。您可以使用调试器或通过检查input.size()或使用input.at(i).
事实证明,它size_t可以转换为std::complex<double>,并且这一行:
std::vector<std::complex<double>> input{kBins, {0.0, 0.0}};
正在构造一个具有两个元素的向量,即使kBins = 64! 似乎正在选择vector采用 a的构造函数std::initializer_list<std::complex<double>>,kBins并且已隐式转换为std::complex<double>.
解决这个问题的一种方法是以不同的方式初始化您的向量,使用auto关键字来避免最烦人的解析,并使用括号而不是花括号来避免意外传递 a std::initializer_list:
auto input = std::vector<std::complex<double>>(kBins, {0.0, 0.0});`
通过此更改,(范围检查)代码运行时不会出错。