【C++】C++中const与constexpr的比较

先说结论
相同点:const和consexpr都是用来定义常量的。
不一样点:const声明的常量,初始值引用的对象不必定是一个常量;constexpr声明的常量,初始值必定是常量表达式。ios

 

constexpr是c++11标准添加的关键字。c++

 

之因此说const声明的常量,初始值不必定是一个常量,主要是从引用和指针的角度出发的。若是初始化const时候,指定一个固定的字面值常量,那么它引用的确定是常量。spa

const int i = 10;
constexpr int j = 20;

这种状况下,i和j都是常量,并且它们引用的也是一个常量(由于是固定的字面值)。那么若是它们引用的不是固定的字面值,而是指针和引用呢?接下来笔者将从引用和指针的角度出发,解释const和constexpr的区别:指针

const与引用

经过以下语法能够声明一个常量int类型引用:c++11

const int &v;

注意这里的v是一个常量int引用,也就是说,v是确定是一个int类型的常量引用(值不能改变),应该给它赋值常量int类型,若是咱们给它赋值变量int类型会怎么样呢?看下面的案例。
例如:code

#include <iostream>
using namespace std;
int main(){
    int a = 20;
    const int &b = a;//引用a,常量int引用b引用了很是量inta
    cout << "a = " << a << ", b = " << b << endl;
    a = 10;//能够经过a改变变量的值
    cout << "a = " << a << ", b = " << b << endl;
    //b = 20;//出错,不能够经过b改变变量的值,由于b一个常量引用,因此不能经过b去改变。
    return 0;
}

结果:对象

a = 20, b = 20
a = 10, b = 10

上面的案例中,a是一个变量,b是一个常量引用。a变量的值不能经过b来改变,可是能够经过a来改变,由于a不是常量,b是常量引用(b认为本身引用的是一个常量,实际却不是)。blog

const与指针

能够经过以下的方式,来声明一个常量指针。ci

int *const p;

p首先是一个常量,而后再是一个指针,而且这个指针指向一个int类型。

下面的案例io

#include <iostream>
using namespace std;
int main(){
    int i = 10;
    int *const p = &i;//指向很是量的常量指针p,指向了很是量i
    cout << "i = " << i << ",*p = " << *p << endl;
    i = 20;
    cout << "i = " << i << ",*p = " << *p << endl;
    *p = 30;
    cout << "i = " << i << ",*p = " << *p << endl;
    int j = 0;
    //p = &j;//出错
    return 0;
}

输出

i = 10,*p = 10
i = 20,*p = 20
i = 30,*p = 30

上面的案例中p是一个常量类型的指针,而且指向一个很是量int对象。因为p是指针,因此*p解地址后其实是变量i,因此能够经过*p改变变量的值。可是p = &j语句,会改变p变量中存储的地址(初始化时存储的是变量i的地址),因为p是常量,因此p中的值是不能改变,所以p = &j会报错。

 

固然能够这样定义

const int *const p;

这样的话,p是一个常量指针,而且指向常量int类型。
例如:

#include <iostream>
using namespace std;
int main(){
    int i = 10;
    const int *const p = &i;//指向常量int的常量指针p,指向了很是量i
    cout << "i = " << i << ",*p = " << *p << endl;
    i = 20;
    cout << "i = " << i << ",*p = " << *p << endl;
    //*p = 30;//出错
    int j = 0;
    //p = &j;//出错
    return 0;
}

输出结果:

i = 10,*p = 10
i = 20,*p = 20

虽然常量指针p应该指向一个常量int类型,可是笔者给它一个很是量int类型的地址,这样一来,p会认为它指向的是一个常量int类型,因此当经过*p = 30改变它的值时,不能经过。可是经过i依然能够修改。

小结:
常量引用能够引用很是量,很是用引用不能引用经常使用。
指向常量的指针能够指向一个很是量,指向很是量的指针不能指向常量。

从逻辑上能够这样理解:由于很是量具备可读可写的功能,常量只有可读的功能;当常量引用很是量时,常量只指望能够读数据,很是量不只提供了读数据,并且很是量还能够写数据(修改),所以常量引用很是量能够知足常量的需求,能够经过;返过来,常量不可以知足很是量的需求,因此不能经过。

int a = 10;
const int &b = a;//正确,b只须要读数据,a能够读数据,因此能够经过。

const int c = 10;
int &d = c;//错误,d须要读数据和写数据,c只能提供读数据,因此不经过。

int e = 10;
const int *f = &e;//正确,*f只须要可以读数据,e能够读数据,因此能够经过。

const int g = 10;
int *h = &g;//错误,*h须要读数据和写数据,g只能提供读数据,因此不经过。

上面笔者总结的规律还有一些须要补充,在不改变const对象的操做中还有一种是初始化,若是一个利用对象去初始化另一个对象(引用和指针除外,这里主要是指拷贝),则他们是否是const都可有可无:

int i = 42;
const int ci = i; // 正确:i的值被拷贝给了ci
int j = ci; //正确 : ci的值被拷贝给了j

尽管ci是const类型,j是int类型。ci的常量特征仅仅在执行改变ci的操做时才会发挥做用,当用ci初始化j时,更本无需在乎ci是否是一个常量。拷贝一个对象的值不会改变它,一旦拷贝完成,新的对象和原来的对象就没什么关系了。

 

constexpr

在上面的说过了const的特色,能够得出,当const变量引用或指向某个变量时,被引用或指向的变量是不能肯定是不是一个常量的。C++11标准提供了constexpr关键字,被constexpr修饰的变量的初始值必须是常量表达式,也就是说,被constexpr修饰的变量,确定是常量,并且引用常量表达式。constexpr int m = 10;//20是常量表达式constexpr int n = m + 1;//m+1是一个常量表达式constexpr const int *p = &m;//错误,&m不是一个常量表达式constexpr const int &r = m;//错误,m不是一个常量表达式

相关文章
相关标签/搜索