C++11 新特性之constexpr关键字

       本文是C++11新特性介绍的第十八部分,涉及到constexpr相关的新特性。

语义上的差别

       首先,我们来看看《C++Primer》怎么说的:
       const:有时我们希望定义这样一种变量,它的值不能被改变。例如,用一个变量来表示缓冲区的大小。使用变量的好处是当我们觉得缓冲区大小不再合适时,很容易对其进行调整。另一方面,也应随时警惕防止程序一不小心改变了这个值。为了满足这一要求,可以用关键字const对变量类型加以限定。
       constexpr(常量表达式):是指值不会改变并且在编译过程就能得到计算结果的表达式。
       从以上两段话,我们可以总结出const和constexpr的关系,即如果变量用constexpr修饰,那么变量也具有const的特性;如果变量用const修饰,不能说明变量具有constexpr的特性。
       从语义上讲,const更像是“read only”,而constexpr更像是“const”。
       接下来,我们来聊一聊为什么要引入constexpr?

常量表达式的优势

       常量表达式的优点是将计算过程转移到编译时期,那么运行期就不再需要计算了,程序性能也就提升了。

const时期的常量表达式

       一个对象(或表达式)是不是常量表达式由它的数据类型和初始化值共同决定的,例:

1
2
3
4
const int a = 20; // a是常量表达式
const int b = a + 1; // b是常量表达式
int c = 7; //c不是常量表达式
const int d = getlength(); //d不是常量表达式

       其中d不是常量表达式的原因是,尽管d本身是一个常量,但它具体的值需要在运行期才能获得,所以不是常量表达式。
       第四句代码就是我们常常说的“伪优化”,误以为这段热点语句已经改成了常量表达式,性能将会有所提升,但其实,并没有啊……

constexpr时期的常量表达式

       为了能明确的表示这段代码一定是常量表达式,在C++11中,引入了constexpr,有了它,我们来看看abcd四个变量的变化:

1
2
3
4
constexpr int a = 20; // a是常量表达式
constexpr int b = a + 1; // b是常量表达式
int c = 7; //c不是常量表达式
constexpr int d = getlength();

       其中变量d有两种情况:
       (1)当getlength()函数也是constexpr时,那么d就是常量表达式
       (2)当getlength()函数不是constexpr时,此时编译会报错。
       即编译器帮助我们检查了常量表达式。
       所以,一般来说,当你认为变量一定是常量表达式,那就把它声明成constexpr类型吧。

实测下的性能差别

       为了让大家更加直观的感受常量表达式和普通表达式的性能差别,请看以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
constexpr int Calculate1 (int x, int y)
{
return x * y * 32 / 14;
}
int Calculate2 (int x, int y)
{
return x * y * 32 / 14;
}
int main()
{
uint64_t start, end;
start = GetMicroSeconds();
for(int i = 0;i < 100000; i++)
{
//也可以换成const修饰,也是常量表达式
constexpr int ret = Calculate1 (11, 12);
}
end = GetMicroSeconds();
cout<<"spend time: "<<end-start<<" us"<<endl;
start = GetMicroSeconds();
for(int i = 0;i < 100000; i++)
{
//不能用constexpr修饰,不是常量表达式,会编译报错
int ret = Calculate2 (11, 12);
}
end = GetMicroSeconds();
cout<<"spend time: "<<end-start<<" us"<<endl;
return 0;
}

       这段代码比较简单,一个常量表达式和一个非常量表达式,都进行相同的计算,都循环10w次,然后记录各自的总耗时,单位是微秒。
       打印结果如下:

1
2
spend time: 182 us
spend time: 929 us

       大家可以看到,接近5倍的性能差别,这要是发生在高性能开发中,将是一次不错的性能提升。

文章目录
  1. 1. 语义上的差别
  2. 2. 常量表达式的优势
  3. 3. const时期的常量表达式
  4. 4. constexpr时期的常量表达式
  5. 5. 实测下的性能差别