为什么-O3 downcast/change const 引用变量的值?

Why does -O3 downcast/change the value of a const reference to a variable?

#include <iostream>
#include <stdint.h>

class Test {
  public:
  Test(const int64_t & val) : val_(val) {
    std::cout << "initialized: " << val_ << std::endl;
  }
  void print() {std::cout << "reference val: " << val_ << std::endl;}

  private:
  const int64_t & val_;
};


int main() {
  long long int input_val= 1628020800000000000L;
  auto t = Test(input_val);
  std::cout << "input_val: " << input_val << std::endl; 
  t.print();
}

如果您在没有优化构建的情况下进行构建,您会得到以下结果:

g++ main.cpp -std=c++17
initialized: 1628020800000000000
input_val: 1628020800000000000
reference val: 1628020800000000000

如果您使用优化的构建进行构建,例如-O3,你得到以下内容:

g++ main.cpp -std=c++17 -O3
initialized: 1628020800000000000
input_val: 1628020800000000000
reference val: 0

我猜这种差异是由于 input_val 的 casting/treatment 属于 long long int 类型,但我不太明白为什么会这样。我认为 long 至少是 32 位,而 long long 至少是 long long 的两倍宽。由于引用是 const int64_t,我认为不会有任何转换问题。

我意识到,如果我将 long long int 切换为 int64_t,这将不是问题,但我想了解发生这种情况的原因。

g++/gcc 版本:

g++ (GCC) 9.1.1 20190605 (Red Hat 9.1.1-2) Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

编辑: 此代码的原始版本将 input_val(原始 static_val)作为全局静态变量。我将示例更改为更简单,因为问题不是基于变量是全局静态变量。

问题是转换。

int64_tlong long int 不是一回事。 所以当这个构造函数被调用时:Test(const int64_t & val) int64_t 类型的临时值是从 long long int.

创建的

所以结果是 const int64_t & val_; 持有对生命周期在调用 Test::print 之前结束的临时对象的引用。 地址清理器 finds issue quite nicely.

当你统一类型时它起作用了:https://godbolt.org/z/nGKa6azE8

注意我添加了检查 int64_t 是什么类型,它匹配 long int 构建 64 位和 long long int 构建 32 位。