C++进阶(四)const、volatile、mutable关键字

  

const 关键字用法

  C语言中,可以使用#define 定义常量,编译器在预处理阶段直接将宏替换,在C++中,使用const 关键字来定义常量,如常量字符串等。常量存放在常量区(常量区只读不可写)。const 常量在运行时被操作系统载入常量区,属于运行时常量。

  C++const 有以下几种用法:const 对象、常量引用、常量指针和const 成员函数。下面从这4个方面介绍 const 关键字。

用法一:const在类中的使用

   使用const 对象时,在类中必须定义 const 成员函数,const对象只能调用 const 成员函数。

class Test_const{
public:
    int getVar(){
        return var;
    }

    int getVar() const{
        cout << "int getVar() const" << endl;
        return var;
    }

private:
    int var;
};

int main(){
    const Test_const ct = Test_const();
    cout << ct.getVar() << endl;
    return 0;
}

  编译执行,const 对象调用 const 成员函数,输出如下。如果类中不定义const 成员函数,则会编译失败。

int getVar() const
0

用法二:常量引用

  函数参数经常会使用常量引用来作为形参,使用常量引用的好处是1. 不可修改传入参数 2. 引用传递(值传递与引用传递的区别略)。特别是对于变量占用空间巨大的情况下,使用常量引用,会显著提高程序执行效率。

ReturnType func(const ClassName& param){
	// ...
}

对于基本类型,如intdouble 等,可以直接使用 const int/double

  

用法三:常量指针

  最令人混淆的就是常量指针、指针常量,这里推荐《C++ Primer》的理解方式,从右向左进行推导其含义。

const int* cpV1;		// pointer to const int , 指向常量的地址,值不可变
int const* cpV2;		// pointer to const int , 同上
int* const pcV;			// const pointer to int , 指向int类型的指针常量,地址不可修改

测试程序及输出结果如下

void constPointer(){
    const int i = 10;
    const int* pci = &i;

    const int j = 20;
    pci = &j;					// 指针可修改
    cout << *pci<< endl;		//   20

    int const* pci1 = &i;
    pci1 = &j;    
    cout << *pci1 << endl;		//   20

    int k = 99;
    int * const cpi = &k;
    *cpi = 9;					// 指针指向的值可修改
    cout << *cpi << endl;    	// 9
}

引用与指针的区别
  简单来说,指针是指向变量的内存地址,而引用是变量别名。指针可以为空,而引用不为空,必须进行初始化。更进一步来说,在C++ 中,编译器将指针常量(constant pointer, 不可改变指向的指针)作为引用的内部实现,即TypeName& var等价于 TypeName* const var,在编译时,所有的var 会被编译为 *var ,所以引用会修改原本输入参数的值。

volatile

  首先思考一个问题,const 变量是否可以修改?下面给出两个示例程序,尝试体会一下const 变量。

示例程序1:修改局部const 变量

int main(){
    int j = 6;
    cout << &j << endl;			// 0x61ff08

    const int var = 10;
    cout << &var << endl;		// 0x61ff04

    int* pvar = (int*)(&var);
    *pvar = 99;
    cout << pvar << endl;		// 0x61ff04
    cout << *pvar << endl;		// 99
}

示例程序2:全局变量 const

const int var = 10;

int main(){
    int j = 6;
    cout << &j << endl;			// 0x61ff08

    cout << &var << endl;		// 0x40506c

    int* pvar = (int*)(&var);
    *pvar = 99;					// Process finished with exit code -1073741819 (0xC0000005)
    cout << pvar << endl;
    cout << *pvar << endl;

	return 0;
}

示例程序3:全局变量 const volatile

const volatile int var = 10;
int g_i = 11;

int main(){
    int j = 6;
    cout << &j << endl;			// 0x61ff08

    cout << &var << endl;		// 1, var为volatile int 类型,operator<<并没有重载,所以需要强制转换为(int*)类型输出
    cout << (int*)&var << endl;	// 0x404004
	cout << &g_i << endl;		// 0x404008
	
    int* pvar = (int*)(&var);
    *pvar = 99;
    cout << pvar << endl;		// 0x404004
    cout << *pvar << endl;		// 99

	reutrn 0;
}

  示例1可以运行成功,其中const 局部变量与普通变量一样,存放在栈区,可以通过地址修改栈区的值。而示例2在运行时直接退出,编译结果如下

0x61ff08
0x40506c

Process finished with exit code -1073741819 (0xC0000005)

可以看到全局区的 const 兑现与普通的栈区地址不同,其存放在常量区,该内存区域的值只读不可修改。所以,当进行修改操作时,程序出错退出。示例3使用 volatile 关键词修饰 const 对象, 其地址与全局变量g_i的地址相邻,其存放在静态区(全局变量区),所以可以通过地址进行修改。
  volatile 关键字的作用:指示编译器该变量是可变的,对该变量无需进行优化。

mutable

  mutable 关键字含义是可变的,与const 关键字相反,只能用来修饰类的成员变量。其作用是,修改 mutable 修饰的变量,并不影响对象的值。如示例程序4所示:

#include <iostream>
using namespace std;

class Test{
public:
    Test():m_count(0), m_i(10){};

    int getI() const{
        m_count++;		// const 成员函数中修改类成员变量,因为该变量被 mutable 修饰
        return m_i;
    }

    int callingTimes() const{
        return m_count;
    }
private:
    int m_i;
    mutable int m_count;
};


int main(){
    Test t = Test();

    cout << t.getI() << endl;
    cout << t.getI() << endl;
    cout << t.getI() << endl;
    cout << t.getI() << endl;
    cout << t.getI() << endl;

    cout << "t.getI() called times:  " << t.callingTimes() << endl;

    return 0;
}

  mutable 的使用场景:

  1. 对象内部使用 mutex 保证线程安全
  2. 缓冲区用于暂存数据
  3. 用于类内部的引用计数

  

巨人的肩膀

  1. volatile 关键字如何使用 - Stackoverflow
  2. C++地址值为1(情况说明)- CSDN
  3. volitile 变量的地址 - stackoverflow
  4. C++中的mutable关键字 - 博客园

一键三连是对我的支持与鼓励!欢迎关注编程小镇,每天学一点新姿势😄。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值