1. constexpr 与 const
const 指的是编译期常量和运行时常量
constexpr 指编译期常量
int var_1 = 111; // 正确 var_1 是一个普通的变量,既不是编译期常量,也不是运行时常量
const int var_2 = 222; // 正确 var_2 是一个编译期常量
const int var_3 = var_1; // 正确 var_3 是一个运行时常量
constexpr int var_4 = 333; // 正确 var_4 是常量表达式,即为编译期常量
constexpr int var_5 = var_1; // 错误 var_5 不是编译期常量,因为 var_1 的值,需要程序的执行到达其所在的声明处时才初始化
2. constexpr 常量会被 Visual Studio 优化
class MyClass3 {
public:
static constexpr int kUserDataKey = 1;
};
class MyClass4 {
public:
static constexpr int kUserDataKey = 1;
};
int main() {
char sz[1024]{ 0 };
sprintf_s(sz, "MyClass3::kUserDataKey=%p | MyClass4::kUserDataKey=%p",
&MyClass3::kUserDataKey, &MyClass4::kUserDataKey);
std::cout << sz << std::endl;
return 0;
}
// 使用VS2017,编译运行,结果如下:
// Debug
MyClass3::kUserDataKey=00989B78 | MyClass4::kUserDataKey=00989B7C
// Release
MyClass3::kUserDataKey=00D53160 | MyClass4::kUserDataKey=00D53160
通过输出内容看出,同一段代码在Debug和Release编译运行后,输出的结果不同,后来发现是Release版本编译器会启动【/GL (Whole Program Optimization)】优化导致的。因为constexpr的语义就是编译期常量,所以编译器如果两个constexpr常量的值相同,则只分配一块内存存放此常量,所以如果你是用这个静态成员的地址做key的话就肯定出问题了,因为两个key是一样的(好坑。。。)。
3. /GL (Whole Program Optimization) 优化
MSDN 说明
Remarks
Whole program optimization allows the compiler to perform optimizations with information on all modules in the program. Without whole program optimization, optimizations are performed on a per module (compiland) basis.
Whole program optimization is off by default and must be explicitly enabled. However, it is also possible to explicitly disable it with /GL-.
With information on all modules, the compiler can:
-
Optimize the use of registers across function boundaries.
-
Do a better job of tracking modifications to global data, allowing a reduction in the number of loads and stores. (应该就是这一条了,会尽量减少全局变量的存储)
-
Do a better job of tracking the possible set of items modified by a pointer dereference,
reducing the numbers of loads and stores. -
Inline a function in a module even when the function is defined in another module.
4. 汇编看下 constexpr 常量
5. 总结
编译器会对两个值相等的constexpr常量,只分配一块内存存放此常量值,所以如果你是用这个常量的地址做key的话就肯定出问题了,但是使用常量值就没问题。