const限定符


const可以用于定义变量,它的值不能被改变。

const int bufSize = 512;


如果有代码试图修改这个变量,就会发生编译错误。


指针和const


const当然也可以用于修饰指针,但是会带来一些混乱,例如:


const double pi = 3.14;
const double *cptr = π //指向常数的指针
*cptr = 4; //编译错误

double var = 45;
double *const pvar = &var; //指向变量为常数
*pvar = 40; //正确


不大容易区分到底谁不能变,这时可以试试下面的视角:


const double*
double* const pvar = &var; //指针变量为常数


常量表达式


const限定符只能保证初始化之后不会被修改,而变量的值是编译阶段就可以确定的还是到执行时才能确定都可以。关于这一点C++中有一个常量表达式的概念,指的是值固定并且在编译过程就能确定计算结果的表达式。例如:


const int max_files = 20;   //20是字面值
const int limit = max_files + 1; //max_files为常量表达式,1是字面值。
const int sz = get_size(); //sz不是常量表达式。


上面的表达式同时满足两个条件:一是变量本身为const类型,二是初始值必须为字面值或者常量表达式。


如果变量类型不是const,那么无论它的初始值是不是常量表达式,它就只是一个变量;如果初始值不是常量表达式,那个变量的值就无法在编译期间得确定只能在执行时占用CPU开销来赋值。


变量的值在编译期间决定,带来的好处就是提高效率,例如例子中的limit的表达方式,在照顾可读性的同时,又不会影响执行效率。


constexpr变量


一般来说,在日益复杂的系统中确定变量的初始值到底是不是常量表达式并不是一件容易的事。为了解决这个问题C++11允许将变量声明为constexpr类型以便由编译器验证变量的值是否是一个常量表达式。


变量声明为constexpr类型,就意味着一方面变量本身是常量,也意味着它必须用常量表达式来初始化。


constexpr int mf = 20;
constexpr int limit = mf + 1;


如果初始值不是常量表达式,那么就会发生编译错误。


constexpr函数


除了能用常量表达式初始化constexpr变量以外,还可以使用constexpr函数。它是指能用于常量表达式的函数,也就是说它的计算结果可以在编译 时确定。定义的方法就是在返回值类型前加constexpr关键字。但是为了保证计算结果可以在编译是确定,必须满足以下条件:


  1. 返回值和形参必须都是字面值类型。
  2. 函数中只能有一条return语句。


例如下面的计算阶乘的constexpr函数。


constexpr long long factorial(int n){
return n <= 1? 1 : (n * factorial(n - 1));
}
constexpr long long f18 = factorial(20);

可以用它来初始化constexpr变量。所有计算都在编译时完成。比较有趣的是像溢出这样错误也会在编译是被检出。


简单地说


constexpr可以


  1. 加强初始值的检查
  2. 计算的时机从运行时提前到编译时,比宏定义效率更高。



阅读更多更新文章,请扫描下面二维码,关注微信公众号【面向对象思考】


C++11新特性(4)- const, const expression和constexpr_字面值