【C++】C++中const与constexpr的比较
先说结论
相同点:const和consexpr都是用来定义常量的。
不同点:const声明的常量,初始值引用的对象不一定是一个常量;constexpr声明的常量,初始值一定是常量表达式。
constexpr是c++11标准添加的关键字。
之所以说const声明的常量,初始值不一定是一个常量,主要是从引用和指针的角度出发的。如果初始化const时候,指定一个固定的字面值常量,那么它引用的肯定是常量。
const int i = ;
constexpr int j = ;
这种情况下,i和j都是常量,而且它们引用的也是一个常量(因为是固定的字面值)。那么如果它们引用的不是固定的字面值,而是指针和引用呢?接下来笔者将从引用和指针的角度出发,解释const和constexpr的区别:
const与引用
通过如下语法可以声明一个常量int类型引用:
const int &v;
注意这里的v是一个常量int引用,也就是说,v是肯定是一个int类型的常量引用(值不能改变),应该给它赋值常量int类型,如果我们给它赋值变量int类型会怎么样呢?看下面的案例。
例如:
#include <iostream>
using namespace std;
int main(){
int a = ;
const int &b = a;//引用a,常量int引用b引用了非常量inta
cout << "a = " << a << ", b = " << b << endl;
a = ;//可以通过a改变变量的值
cout << "a = " << a << ", b = " << b << endl;
//b = 20;//出错,不可以通过b改变变量的值,因为b一个常量引用,所以不能通过b去改变。
return ;
}
结果:
a = 20, b = 20
a = 10, b = 10
上面的案例中,a是一个变量,b是一个常量引用。a变量的值不能通过b来改变,但是可以通过a来改变,因为a不是常量,b是常量引用(b认为自己引用的是一个常量,实际却不是)。
const与指针
可以通过如下的方式,来声明一个常量指针。
int *const p;
p首先是一个常量,然后再是一个指针,并且这个指针指向一个int类型。
下面的案例
#include <iostream>
using namespace std;
int main(){
int i = ;
int *const p = &i;//指向非常量的常量指针p,指向了非常量i
cout << "i = " << i << ",*p = " << *p << endl;
i = ;
cout << "i = " << i << ",*p = " << *p << endl;
*p = ;
cout << "i = " << i << ",*p = " << *p << endl;
int j = ;
//p = &j;//出错
return ;
}
输出
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 = ;
const int *const p = &i;//指向常量int的常量指针p,指向了非常量i
cout << "i = " << i << ",*p = " << *p << endl;
i = ;
cout << "i = " << i << ",*p = " << *p << endl;
//*p = 30;//出错
int j = ;
//p = &j;//出错
return ;
}
输出结果:
i = 10,*p = 10
i = 20,*p = 20
虽然常量指针p应该指向一个常量int类型,但是笔者给它一个非常量int类型的地址,这样一来,p会认为它指向的是一个常量int类型,所以当通过*p = 30改变它的值时,不能通过。但是通过i依然可以修改。
小结:
常量引用可以引用非常量,非常用引用不能引用常用。
指向常量的指针可以指向一个非常量,指向非常量的指针不能指向常量。
从逻辑上可以这样理解:因为非常量具有可读可写的功能,常量只有可读的功能;当常量引用非常量时,常量只期望可以读数据,非常量不仅提供了读数据,而且非常量还可以写数据(修改),因此常量引用非常量可以满足常量的需求,可以通过;返过来,常量不能够满足非常量的需求,所以不能通过。
int a = ;
const int &b = a;//正确,b只需要读数据,a可以读数据,所以可以通过。 const int c = ;
int &d = c;//错误,d需要读数据和写数据,c只能提供读数据,所以不通过。 int e = ;
const int *f = &e;//正确,*f只需要能够读数据,e可以读数据,所以可以通过。 const int g = ;
int *h = &g;//错误,*h需要读数据和写数据,g只能提供读数据,所以不通过。
上面笔者总结的规律还有一些需要补充,在不改变const对象的操作中还有一种是初始化,如果一个利用对象去初始化另外一个对象(引用和指针除外,这里主要是指拷贝),则他们是不是const都无关紧要:
int i = ;
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;//错误
constexpr const int &r = m;//错误
【C++】C++中const与constexpr的比较的更多相关文章
- C++中const与constexpr区别
对于对象来说 const指的是编译期常量和运行时常量,两者并没有区分 constexpr特指编译期常量 对于函数来说 const可以修饰类的成员函数,被修饰的函数在执行期间不会改变对象的值. clas ...
- C++总结:C++中的const和constexpr
C++中的const可用于修饰变量.函数,且在不同的地方有着不同的含义,现总结如下. const的语义 C++中的const的目的是通过编译器来保证对象的常量性,强制编译器将所有可能违背const对象 ...
- 3、const与constexpr
初遇到constexpr真的是有点懵比,看了很多博客也没看懂,不知道是我太笨,还是别人写的太深奥?总之经过一番折腾算是入门了.一下是我个人总结,有不对的地方望指出. 一.学习const与constex ...
- C、C++中const的区别
C语言中: 被const修饰的变量,仍然是变量.虽然不能用C语法给这个变量改变值,但他本质上还是变量. C编译器会给它分配空间. C中,const默认使用的是外部链接. C++中: 被const修饰的 ...
- JavaScript中const、var和let区别浅析
在JavaScript中有三种声明变量的方式:var.let.const.下文给大家介绍js中三种定义变量的方式const, var, let的区别. 1.const定义的变量不可以修改,而且必须初始 ...
- C/C++中const的用法 分类: C/C++ 2015-07-05 00:43 85人阅读 评论(0) 收藏
const是C语言的关键字,经C++进行扩充,变得功能强大,用法复杂.const用于定义一个常变量(只读变量),当const与指针,引用,函数等结合起来使用时,情况会变得复杂的多.下面将从五个方面总结 ...
- C++中const 的各种用法
C++中const 关键字的用法 const修饰变量 const 主要用于把一个对象转换成一个常量,例如: ; size = ; // error: assignment of read-only v ...
- (转) C/C++中const关键字详解
文章转自 http://www.cnblogs.com/yc_sunniwell/archive/2010/07/14/1777416.html 为什么使用const?采用符号常量写出的代码更容易维 ...
- 实例讲述PHP面向对象的特性;;;php中const与define的使用区别
php中const与define的使用区别 1.const:类成员变量定义,一旦定义且不能改变其值. define:定义全局常量,在任何地方都可以访问.2.define:不能在类中定义,而const可 ...
随机推荐
- ul无点标签左移
ul标签去除掉点,ul li 块仍会在原来的位置,即与上一块内容相对右移一点. 这是 ul标签的默认padding值导致的. 修改style或者CSS中的class为如下即可 { list-style ...
- Java数组实现循环队列的两种方法
用java实现循环队列的方法: 1.添加一个属性size用来记录眼下的元素个数. 目的是当head=rear的时候.通过size=0还是size=数组长度.来区分队列为空,或者队列已满. 2.数组中仅 ...
- Java内存管理-掌握类加载器的核心源码和设计模式(六)
勿在流沙筑高台,出来混迟早要还的. 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 上一篇文章介绍了类加载器分类以及类加载器的双亲委派模型,让我们能够从整体上对类加载器有 ...
- 同一台电脑上个人的github账户如何与公司的gitlab账户共存
前些天,写了篇博客 开发环境之git:团队协作git工作流与常用命令. 主要是回顾其中的第一小节基本配置. 但是对于很多程序员而言,我们不仅有公司的gitlab账户做公司的业务,也会有自己个人的git ...
- Java 的Event机制浅析
https://blog.csdn.net/kehyuanyu/article/details/23540901
- mysql主从配置和galera集群
mariadb主从 主从多用于网站架构,因为主从的同步机制是异步的,数据的同步有一定延迟,也就是说有可能会造成数据的丢失,但是性能比较好,因此网站大多数用的是主从架构的数据库,读写分离必须基于主从架构 ...
- python urllib 库
urllib模块中的方法 1.urllib.urlopen(url[,data[,proxies]]) 打开一个url的方法,返回一个文件对象,然后可以进行类似文件对象的操作.本例试着打开google ...
- SpringBoot整合Mybatis-Plus
这篇文章介绍一个SpringBoot整合Mybatis-Plus,提供一个小的Demo供大家参考. 已经很久没有写文章了,最近家里有点事刚刚处理完,顺便也趁机休息了一段时间.刚回到公司看了一下码云,发 ...
- C#最简单的连接数据库的方法
在vs2010下建立项目(可以是WEB或者是FORM窗体应用程序),在VS2010中,找到“服务器资源管理器”,右击“数据连接”.在添加连接中设置服务器名(登录SQL Server时的服务器名称,可以 ...
- 潭州课堂25班:Ph201805201 django 项目 第二十八课 新闻elasticsearch搜索前后功台能实现 (课堂笔记)
后端功能实现 文件,类,字段,命名不要改动, 在apps/news/search_indexes.py中创建如下类:(名称固定为search_indexes.py) # -*-# -*- coding ...