为什么编译器优化会破坏我的代码?

Why is compiler optimisation breaking my code?

我在使用这段代码时遇到了一些问题。它在调试模式下工作,但在发布模式下会错误地为某些 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 向量未按预期进行初始化。它的大小始终为二,您观察到的所有奇怪结果都是由于读取矢量越界而导致的未定义行为的结果。您可以使用调试器找到它,或者通过检查 input.size() 或使用 input.at(i).

事实证明 size_t 可以转换为 std::complex<double>,并且这一行:

std::vector<std::complex<double>> input{kBins, {0.0, 0.0}};

constructing a vector with two elements,虽然kBins = 64!似乎正在选择采用 std::initializer_list<std::complex<double>>vector 构造函数,并且 kBins 已隐式转换为 std::complex<double>.

解决这个问题的一种方法是以不同方式初始化向量,使用 auto 关键字来避免最令人烦恼的解析,并使用圆括号而不是大括号来避免意外传递 std::initializer_list

auto input = std::vector<std::complex<double>>(kBins, {0.0, 0.0});`

通过此更改,the (range-checked) code runs without errors