volatile与const综合分析

在C/C++ 编程中,volatile与const关键字一贯容易让人困惑,固然,新手可能历来不用,可是 在高质量和稳健的程序中,这两个关键字 是至关重要的。程序员

    相比const,volatile关键字的发展(变化)较少,从C到C++的演变中,一直保持着 它的语义,所以,咱们先从volatile来了解下,这两个关键字面试

1、volatile

1.volatile 的基础 认知:

volatile 的英文 释义是 容易 挥发的,编程

    做为 关键字,能够 记忆为 它修饰的 变量 是 不稳定的,可能被其余地方的某些方式改变,所以为了 获取正确的值,编译器 不应对其作优化,好比为了 获取较快的 读取速度,将它 放入寄存器中等,而是每次都要从它所在的内存中 读取。安全

 

BS在 书中 对 volatile 的定义是:多线程

A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.ide

 

volatile修饰符 意在暗示 编译器,该被修饰的对象 经过该语言未指定的方式改变他的值,所以,积极的优化都应该被消除。函数

 

未指定的方式 ,好比 操做系统,硬件或者其余线程等。学习

    遇到volatile修饰的变量,编译器对访问该变量的代码 再也不进行优化,从而能够提供对特殊地质的稳定访问。优化

    稳定的访问的方式 是 ,系统老是从新从该 变量的 内存中读取数据,即便  它 前面的 指令 刚刚 从该处 读取过数据。spa

2.volatile  修饰指针

咱们可使用 volatile修饰 指针,好比

volatile char * myVolatileStr;
char *volatile strVolatilePtr;

  

volatile 修饰 char*  和 *char 是 有较大区别的,和const修饰同样,volatile能够将其修饰的 内存区域 声明为 易挥发的,也能够将 指针变量自己声明为 易挥发的。一般,有如下注意点:

 注意:(1) 能够把一个非volatile int 赋给 volatile int,可是不能把非volatile对象赋给一个volatile对象。

       (2) 除了基本类型外,对用户定义类型也能够用volatile类型进行修饰。

             (3) C++中一个有volatile标识符的类只能访问它接口的子集,一个由类的实现者控制的子集。用户只能用const_cast来得到对类型接口的彻底访问。此外,volatile向const同样会从类传递到它的成员。

 

3.volatile在 多线程中

 

    在 多线程 中,有些变量是要用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该关键字的做用是防止优化编译器把变量从内存装入CPU寄存器中。若是变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会形成程序的错误执行。volatile的意思是让编译器每次操做该变量时必定要从内存中真正取出,而不是使用已经存在寄存器中的值,

 

下面,来对比学习 下 const,

 

2、const

1.const基础

    在C++中,老手们建议 咱们 尽量的 多使用 const,可是 为啥呢?若是 面试官 问起,你就说,为了程序的稳健性,可是 这和问 锻炼身体为啥呢,保卫祖国 ,没什么 区别。

    const 理论上 是 constant的简写,constant的英文释义是  不变的;恒定的;常常的。可是 不少大神将它理解成了 只读的,readonly,甚至以为 要把这个关键词 替换成readonly。这在gun编译器中也是这么 提错的,颇有意思。

    和volatile同样,const也是对编译器的约束(废话),它明确的告诉 编译器,const修饰的变量 是 不变的,若是出现了 其余地方的对其修饰值的改变,应该在编译期间就报错。这样能大大提升程序的健壮性,固然,对于程序员,在编译期间就发现错误本就是极好的。

2.const修饰局部变量

这是 最基本的用法,如

  

const int i = 5;
int const i = 4;

 

 两者 并没有本质差别,都是表示 变量i是 不变的,

 

    

3.const 与指针

     
const char* str;
char * const str;
char const* str;
const char* const str;
const char const* str;

   

以上,声明了 5种const 与指针的 位置 修饰 关系。
咱们一一说明下:
    声明 1 ,与 const int i,没有区别 ,修饰 其所指向的 内存区域 是 只读的,不容许 修改
    声明 2 ,const 直接修饰 str,即指针变量自己,说明 该指针变量 自己是只读的,可是,其所指向的内存区域仍是能够改变的。
    声明 3 ,与声明1 本质一致,见第2
    声明 4, 声明1 和声明 2 的 合并,其意义也是 2者的 合并
    声明 5 ,错误的声明。
经过以上 分析能够 看出,const与其修饰的哪一个 类型近,就限定了哪一个为只读,这是规定,可是要防止像声明5 那样的 错误声明,由于有两个const都在修饰 char,这明显是错误的。

4.const与引用

    在C++中 ,可使用 const 修饰引用,

5. const修饰函数参数

 
const修饰函数参数是它最普遍的一种用途,它表示函数体中不能修改参数的值(包括参数自己的值或者参数其中包含的值)。
 
 
  1. void function(constintVar);//传递过来的参数在函数内不能够改变(无心义,由于Var自己就是形参)
  2. void function(constchar*Var);//参数指针所指内容为常量不可变
  3. void function(char*constVar);//参数指针自己为常量不可变(也无心义, 由于char* Var也是形参)
 
 
    将参数修饰为常量引用,增长了效率同时防止修改。
修饰引用参数时:
 
 
  1. void function(constClass&Var);//引用参数在函数内不能够改变
  2. void function(const TYPE&Var);//引用参数在函数内为常量不可变
 
 

6. const 修饰函数返回值

 
const修饰函数返回值其实用的并非不少,它的含义和const修饰普通变量以及指针的含义基本相同。
(1) const int fun1() 这个其实无心义,由于参数返回自己就是赋值。
(2) const int * fun2()
    调用时 const int *pValue = fun2();
    咱们能够把fun2()看做成一个变量,那么就是咱们上面所说的1.(1)的写法,即指针内容不可变。
(3) int* const fun3()
调用时 int * const pValue = fun2();
    咱们能够把fun2()看做成一个变量,那么就是咱们上面所说的1.(2)的写法,即指针自己不可变。

7. const修饰类对象/对象指针/对象引用

 
const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是同样。
const修饰的对象,该对象的任何非const成员函数都不能被调用,由于任何非const成员函数会有修改为员变量的企图
例如:
class AAA
{
   void func1();
void func2()const;
}
const AAA aObj;
aObj.func1();//×
aObj.func2();//正确
 
const AAA* aObj =new AAA();
aObj->func1();// ×
aObj->func2();//正确

 

 
 

8. const修饰成员变量

 
const修饰类的成员函数,表示成员常量,不能被修改,同时它只能在初始化列表中赋值。
 
class A
{
   …
   constint nValue;       //成员常量不能被修改
   …
   A(int x): nValue(x){};//只能在初始化列表中赋值
}

 

 

9. const修饰成员函数

 
const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。通常写在函数的最后来修饰。
 
 
 
class A
{
   …
void function()const;//常成员函数, 它不改变对象的成员变量. 也不能调用类中任何非const成员函数。
}

 

 
对于const类对象/指针/引用,只能调用类的const成员函数,所以,const修饰成员函数的最重要做用就是限制对于const对象的使用。
 

10. const常量与define宏定义的区别

 
(1) 编译器处理方式不一样
    define宏是在预处理阶段展开。
    const常量是编译运行阶段使用。
(2) 类型和安全检查不一样
    define宏没有类型,不作任何类型检查,仅仅是展开。
    const常量有具体的类型,在编译阶段会执行类型检查。
(3) 存储方式不一样
    define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。
    const常量会在内存中分配(能够是堆中也能够是栈中)。


3、总结 分析
那么问题来了,理解了 volatile 和 const关键词的使用 场景 ,那么 两者能够同时使用吗?
好比 const volatile int i;这样的声明 是否 有问题呢?
从语义上讲,彷佛不可能,可是 ,这样的声明 其实  是合法的。
    由于const和volatile这两个类型限定符并不矛盾。const表示(运行时)常量语义:被const修饰的对象在所在的做用域没法进行修改操做,编译器对于试图直接修改const对象的表达式会产生编译错误。volatile表示“易变的”,即在运行期对象可能在当前程序上下文的控制流之外被修改(例如多线程中被其它线程修改;对象所在的存储器可能被多个硬件设备随机修改等状况):被volatile修饰的对象,编译器不会对这个对象的操做进行优化。一个对象能够同时被const和volatile修饰,代表这个对象体现常量语义,但同时可能被当前对象所在程序上下文意外的状况修改。
相关文章
相关标签/搜索