【C++】const关键字详解 && volatile关键字了解

1.const修饰符的作用

const是一个语义约束,编译器会强制实施这个约束。它会指明变量或对象的值不能被改变
被const修饰,可以防止意外修改,增强程序的健壮性

2.const常量的存储

  • C++中,被const修饰的变量已经不在是一个变量了,而是一个常量。
    验证:
    在这里插入图片描述

  • 在编译的时候全部替换为const修饰的变量的初始化值,在运行的时候该const变量可通过内存进行修改
    2.1通过内存(指针)可以修改位于栈区的const变量,语法合乎规定,编译运行不会报错,但是在编译的时候所有用到该常量的地方全部被替换成了初始化时所赋予的值,然后再运行的时候无法使用通过指针修改后的值
    在这里插入图片描述
    从汇编角度再次验证我们上图的描述
    在这里插入图片描述
    2.2通过内存(指针)修改位于静态存储区的的const变量,语法上没有报错,编译不会出错,一旦运行就会报告异常。
    在这里插入图片描述

3.const修饰变量

表示该变量的值是只读的,不能被修改
由于const修饰的变量值不可被修改,所以const变量必须被初始化
在这里插入图片描述

4.const修饰指针 && 引用

4.1修饰指针

重点关注 const在 * 的前面还是后面
在这里插入图片描述

4.2修饰引用

const 修饰的引用称为 “常量引用”,常量引用不能直接修改所引用的对象
在这里插入图片描述
一般来说,引用的类型要与其所引用的对象的类型一致
但也有特殊情况:
比如:
const修饰的引用引用相同类型的非const变量
在这里插入图片描述
const修饰的引用类型与所引用对象类型不一致
此时,const修饰的引用并不是引用d(拿下图举例),而是对中间临时变量的引用
在这里插入图片描述

4.3指针与引用的联系

  • 在底层实现原理上,引用是通过指针方式实现的
  • T&可以看做是 T* const类型的指针
    这也就解释了为什么一旦引用一个实体后,就不能在去引用其他实体。本质原因就是底层的const不允许它指向发生改变,也就导致了引用不能改变。
  • const T& 可以看做是 const T* const类型的指针

关于指针与引用的区别联系,感兴趣的朋友移步至指针&&引用

5.const修饰非成员函数

5.1 修饰参数

  • 函数参数列表中被const修饰的参数,在函数体内部不能被修改
    在这里插入图片描述

  • const修饰函数参数对函数重载的影响
    1.参数为普通变量
    在这里插入图片描述
    2.参数为指针变量
    要看const修饰的是哪一部分:
    2.1const修饰指针的指向在这里插入图片描述
    2.2 const修饰指针指向的内容
    在这里插入图片描述
    3.参数为引用类型
    构成重载~因为第一个引用的是变量,而第二个是对常量的引用
    在这里插入图片描述

总结:
1、对于函数值传递的情况,因为参数传递是通过复制实参创建一个临时变量传递进函数的(形参实例化,创建临时对象),函数内只能改变临时变量,但无法改变实参,则这个时候无论加不加const对实参不会产生任何影响。
2、在引用或指针传递函数调用中,因为传进去的是一个引用或指针,这样函数内部可以改变引用改变指针所指向的变量,这时const 才是实实在在地保护了实参所指向的变量
3、在编译阶段编译器对调用函数的选择是根据实参进行的,所以,只有引用传递和指针传递可以用是否加const来重载

5.2 修饰返回值

  • 值传递方式
    函数会将返回值复制到外部临时的存储单元中,加const修饰没有任何价值,因为临时的存储单元本来就具有常性。只能使用他的右值
  • 指针传递方式
    1、int* const fun()
    在这里插入图片描述
    2、const int * fun()int const *fun()
    它两效果等价
    在这里插入图片描述
  • 修饰引用返回值
    使用要点:返回的引用不能是函数内临时变量的引用。

6.const修饰类对象

const修饰类对象时与const修饰变量并无实质不同,只是在于类对象的“改变”定义。
被const修饰的类对象,既不能改变类中的成员变量,也不能调用类中任何非const成员函数
在这里插入图片描述

7.const修饰类成员变量

const修饰的成员变量不能被修改,所以只能在初始化列表中被初始化,和类中的引用成员变量一样
在这里插入图片描述

如果是const修饰的静态成员变量,因为属于整个类,而不是对象,不可以在初始化列表的位置进行初始化。(其实这是static存在的原因,这里是想要强调另外一点,见下图)
在这里插入图片描述

8.const修饰类成员函数

本质:修饰的是该成员函数隐含的this指针
在这里插入图片描述
const修饰成员函数表示此函数不能对任何成员变量进行修改
一般const写在函数的后面,形如:int func() const;
在这里插入图片描述
下面是4道经典的问题,感兴趣的朋友们移步至 const几个经典问题
在这里插入图片描述

9.mutable关键字

存在的意义:为了突破const的限制而设置的,可以用来修饰一个类的成员变量。被 mutable 修饰的变量,将永远处于可变的状态,即使是 const 函数中也可以改变这个变量的值
在这里插入图片描述
对于const修饰的类对象,也是可以修改mutable修饰的成员变量
在这里插入图片描述

volatile关键字

浅谈我个人对volatile关键字的一些认识:
它被称为 最易变的关键字
作用:保持内存可见性
画图理解:(仅是个人理解,有不对的地方还请海涵)
在这里插入图片描述
对于这种情况,称为系统的优化。
在这里插入图片描述
下面我就通过Linux平台下验证一下:
在这里插入图片描述
编译代码,使用优化命令 -O2
在这里插入图片描述
将代码反汇编,查看汇编代码
在这里插入图片描述
打开a.s,查看汇编代码
在这里插入图片描述
仔细观察上图,我们发现,其实CPU在将value值第一次读进寄存器后,代码执行到最后直接是自己调用自己,连从寄存器取值也不会执行!!

看到这里,验证也就进行了一半了
接下来,我们将value变量用volatile修饰
在这里插入图片描述
OK!那么为什么要有volatile关键字呢?
(以上例说明)
原因是在某些情况下,我们需要时刻读取内存中变量(value)的值在确定程序下一步该如何执行,尽管在我们现在的认知里,只要这个进程不改变内存中变量(value)的值,那么他就会一直运行下去。
那是因为我们没有了解过多线程等相关知识。如果在这种情况下,其他的线程可能会修改内存中value的值,进而导致该循环可能会无法执行。
如果我们用volatile关键字修饰该变量,那么它每次都会从内存读取该数据,也就不会有上面的情况了。

请问:const volatile int a = 10;这条语句可以编译通过吗?
答案是可以的。
那有人就有疑问了,const要求不进行写入,volatile是最易变的关键字,二者之间不冲突吗?
这里volatile的叫法有些迷惑性。volatile的真实含义是在读取数据的时候,每次都要从内存读取。
这里的易变指的是它修饰的变量可能会变化,要编译器注意。并不是说它要求对应变量必须变化。

注意:
const是在编译期间起效果
volatile在编译期间主要影响编译器,形成不优化的代码,进而影响运行。故编译和运行都起效果

结合 const volatile 进一步理解const的存储

const volatile修饰的变量,可以在编译时不用全部替换被const volatile变量被赋予的值,因此可以在运行时使用通过内存修改后的值

1、通过内存(指针)可以修改位于栈区的const volatile变量,语法合乎规定,编译运行不会报错,在编译的时候所有用到该常量的地方不会替换成了定义时初始化的值,在运行的时候可以使用通过指针修改后的值。
在这里插入图片描述
2、通过内存(指针)修改位于静态存储区的的const volatile变量,语法上没有报错,编译不会出错,一旦运行就会报告异常。
在这里插入图片描述

写到这里,就我目前学到的知识来看,我眼中的const就是这样~
当然,后续学习过程中,如果遇到其他的特性,我会回来更新的。
既然都看到这里了,那就三连一波儿,留下你的足迹吧!!!
在这里插入图片描述

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Suk-god

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值