为什么-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_t
与 long 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 位。
#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_t
与 long 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 位。