导读:C++11引入了constexpr对const的补充,因此凡是表示“只读”建议用const,凡是表示“常量表达式”建议使用constexpr。
目录
一、关于const
1、const的功能
在 C++11 之前只有 const 关键字,从功能上来说这个关键字有双重语义:变量只读与常量表达式,举一个简单的例子:
void func(const int num)
{
const int count = 24;
int array[num]; // error,num是一个只读变量,不是常量
int array1[count]; // ok,count是一个常量
int a1 = 520;
int a2 = 250;
const int& b = a1;
b = a2; // error
a1 = 1314;
cout << "b: " << b << endl; // 输出结果为1314
}
当 const 修饰的变量是只读变量时,仅仅是说明不能通过这个只读变量修改内存的值,但是可以通过其他方法修改内存值。 如下:
void func1(const int num)
{
int a = 10;
const int& con_b = a;
cout << con_b << endl;//输出为10
a = 20;
cout << con_b << endl;//输出20,改变了con_b的值大小
}
2、辨别“只读”与“常量表达式”
看了前面的关于 const 的内容,不知道是不是有疑问,const 什么时候为只读变量,什么时候是常量?
(1) 在编译期间能直接确定初始值的 const 标示符,都被作为常量表达式处理。
(2)在运行期间才能确定其初始值的按照只读变量处理。
我们来看以下以下例子:
void test(const int n)//虽然是const修饰,但是n的值只有在运行期间通过实参传递进来才知道其值大小,因此是只读。
{
//字面值类型:算术类型、引用和指针都属于字面值类型,自定义类、IO库,string类型则不属于字面值类型
int a = 10;
const int n1 = 100;//n1被字面值100修饰,在编译期间就能确定其大小
int array[n];//只读变量不能进行初始化数组的大小
int array1[n1];//常量表达式可以进行初始化其大小
const int& n2 = n1;
int array2[n2];//n2仍然是只读,error
int& n3 = a;//error
int array3[n3];//n3仍然是只读
int& n6 = a;//可以通过其他方式修改n6的大小,因此其仍然是只读变量
int array6[n6];//error
const int n4 = n1;
int array3[n4];//表示常量表达式
}
综上,对于常量的判断准则有以下三条:
- 只有用字面量初始化的 const 常量才会进入符号表
- 使用其他变量初始化的 const 常量仍然是只读变量
- 被 volatile 修饰的 const 常量不会进入符号表
二、关于constexpr
1、从本质了解constexpr
在 C++11 中添加了一个新的关键字 constexpr,这个关键字是用来修饰常量表达式的。所谓常量表达式,指的就是由多个或一个常量组成并且在编译过程中就得到计算结果的表达式。
C++ 程序从编写完毕到执行分为四个阶段:预处理、 编译、汇编和链接 4 个阶段,得到可执行程序之后就可以运行了。需要额外强调的是,常量表达式和非常量表达式的计算时机不同,非常量表达式只能在程序运行阶段计算出结果,但是常量表达式的计算往往发生在程序的编译阶段,这可以极大提高程序的执行效率,因为表达式只需要在编译阶段计算一次,节省了每次程序运行时都需要计算一次的时间。
int getValue()
{
int a = 10;
return a;
}
//constexpr 关键字之后就可以在程序中使用它来修改常量表达式,用来提高程序的执行效率。
constexpr int getValue1()//有constexp修饰,
{
int a = 10;
return a;
}
void test()
{
int array[getValue()];//getValue()非常量表达式
int array1[getValue1()];//getValue1()为常量表达式
}
再看以下:
const int m = f(); // 不是常量表达式,m的值只有在运行时才会获取。
const int i=520; // 是一个常量表达式
const int j=i+1; // 是一个常量表达式
constexpr int i=520; // 是一个常量表达式
constexpr int j=i+1; // 是一个常量表达式
2、constexpr修饰函数
(1)函数必须要有返回值,并且 return 返回的表达式必须是常量表达式。
// error,不是常量表达式函数
constexpr void func1()
{
int a = 100;
cout << "a: " << a << endl;
}
// error,不是常量表达式函数
constexpr int func1()
{
int a = 100;
return a;
}
(2)函数必须要有返回值,并且 return 返回的表达式必须是常量表达式。
#include <iostream>
using namespace std;
constexpr int func1();
int main()
{
constexpr int num = func1(); // error
return 0;
}
constexpr int func1()
{
constexpr int a = 100;
return a;
}
总结:在定义常量时,const 和 constexpr 是等价的,都可以在程序的编译阶段计算出结果。但是,在使用中建议将 const 和 constexpr 的功能区分开,即凡是表达“只读”语义的场景都使用 const,表达“常量”语义的场景都使用 constexpr。
(1)const用于修饰不能被修改的对象,但const对象的值通常在程序运行期间才能确定;
(2)constexpr用于修饰常量表达式或可返回常量表达式的constexpr函数,在编译时能确定值;
(3)constexpr函数都是inline函数。
参考文献:
(161条消息) C++ const和constexpr详解_倒地不起的土豆的博客-CSDN博客_constexpr string
(161条消息) constexpr_Gamer_code的博客-CSDN博客_constexpr
(161条消息) 【C++深度解析】9、const 常量?只读变量?_-出发-的博客-CSDN博客_c++ 只读变量《C++ Primer 第五版》