踩了constexpr变量的坑

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 常量

2中的代码反汇编

5. 总结

编译器会对两个值相等的constexpr常量,只分配一块内存存放此常量值,所以如果你是用这个常量的地址做key的话就肯定出问题了,但是使用常量值就没问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值