C++ — const volatile mutable的用法

const volatile mutable 的用法

_______________________________________________



相信const大家对他并不陌生,可能大家在日常的编写代码当中就会时常用到const,但是剩下的两个关键字 不知道我们有

使用 过volatile和mutable两个关键字其实不算特别常用,但是我们一定要知道这个关键字 有什么用,应该怎么用.首

先con st的基本操作我曾经写过一篇博客: const的基本使用

现在我要说一个const操作里面比较骚的一些做法,

举个例子我们以前写过的一个类,我们会使用operator[]来返回一个reference的指向,这个一般情况我们都会写一个

const的也会写一个非const的opeartor[].这是我们最常见的一个代码:

T& operator[](int position)   
{  
    return xxx[position];  
}  
const T& operator[](int position) const  
{  
    return xxx[position];  
}  

这是我们平时写的初级的代码,但是现在当我们要写一个TextBlock内的opeartor[]不单只返回一个referencr了

,也可能执行边界检查,日志访问信息,还有什么数据完善性检验等等一大堆繁琐的代码,这个时候当你实现

operator[] const和 operator[]()  const,的时候两份代码大部分都一样,这里伴随的是代码重复,编译时间变长,

维护代码膨胀等等头疼 的问题. 当然啦,你可以让 上述那些繁琐的函数全部封装的别的函数中,然后分别在

operator[]()和operator[]()co nst当中调用但是你还说重复了一些代码 比如两次return语句,函数调用.真正该做

的是实现operator[]的机能一次并使用它两次。也就是你只需要写一个函数,令另外一个调用这个,这促使我 们将

常 量性 转移. 接下来 见证奇迹我们来看看下面这个代码是怎么实现的上述的操作的:

class TextBlock  
{  
public:  
    ...  
    const char& operator[](std::size_t position) const  
    {  
        ...  
        ...  
        ...  
        return text[position];  
    }  
  
    char& operator[](std::size_t position)  
    {  
        return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);  
    }  
};  

来仔细看这个操作;return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);

首先把*this强制转换为const TextBlock,再然后调用const的operator[],最后再把const的operator[]的返回值的

const常量性取消,然后返回一个非const的值. 这里的调用实在是太妙了,我们可以思考一下,好好想想这里的深意.

但是会有人说,为什么不用const operator[]调用operator[]呢,这样强制两个都可以行的通啊.这样想是错的!

令const版本调用调用no-const版本以避免重复并不是你该做的事情. 记住const所修饰函数的承诺就是我绝对不会修

改你 ,no-const函数可没有这种承诺,所以你让一个const函数去调用一个no-const函数是不现实的. over

其实const有很多可以玩的属性,只要我们想到就可以去实现,这里就说这么一个就ok. 接下来我们来瞧瞧另外两个

关键字.



mutable

———————————————————————————————————————


其实呢,这个关键字的作用就是mutalbe的中文意思是“可变的,易变的”,跟constant是反义词就是我们上边说的

const在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量(mutable只能由于修饰类的

非静态数据成员),将永远处于可变的状态,即使在一个const函数中。


实际运用起来也非常容易,就是你想改变的元素被const修饰了,你就往它前面加上mutable那么你就无敌了..

我就举一个最简单的例子,我定一个AA类,我在AA类中定义一个MT()函数,该函数属性为const属性,再然后我

想在MT()函数中添加该函数执行多少次时,程序编不过去了. 因为const修饰的函数里面的所有值都不能修改.


代码举例:

class AA
{
public:
	void MT() const
	{
		i++;
		cout << "hehe";
		cout << "执行了" << i << "次该程序";
	}

private:
	int i = 0;
};

但是这样编不过去啊,因为MT()函数为const函数,所以不能修改i的值,但是如果我在这里使用mutable关键字的

话,现在我们把i加上mutable关键字,这样它永远就是一个可变的了. 来我们加上去试一试,

class AA
{
public:
	void MT() const
	{
		i++;
		cout << "hehe" << "   ";
		cout << "执行了" << i << "次该程序" << endl;;
	}

private:
	mutable int i = 0;
};

int main()
{
	AA a;
	a.MT();
	a.MT();
	a.MT();
	a.MT();
	return 0;
}

运行结果:



这就是mutable的最简单的一个应用,以后可以根据需求来使用~ 


volatile

______________________________________________________________________


一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地

说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下

面是volatile变量的几个例子:

1.并行设备的硬件寄存器(如:状态寄存器

2.一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)

3.多线程应用中被几个任务共享的变量


看下面例题:

int square(volatile int *ptr)
{
    return *ptr * *ptr;
}

这个程序有什么问题吗? 如果我们不去关心volatile关键字的话,那么这个程序你怎么看都会觉得没多大问题.但是这里

面问题大这ne, 首先参数声明为volatile就是表明*ptr可能会随时改变.上述代码运行时,编译器可能产生这样的代码:

int square(volatile int *ptr)
{
    int a,b;
    a = *ptr;
    b = *ptr;
    return a * b;
}


因为你的*ptr是随时都可以意想不到的变化,所以有可能a*b的时候,a b的值不相同. 这样你就得到一个错误的结果

改正后的程序:

int square(volatile int *ptr)
{
    int a;
    a = *ptr;
    return a * a;
}


第二个问题,看如下代码:


#include<iostream>  
#include<Windows.h>  
#include<assert.h>  
  
using namespace std;  
  
int main()  
{  
    const int a = 2;  
    int *p = const_cast<int*>(&a);  
    *p = 3;  
    cout << a << endl;  
    system("pause");  
    return 0;  
}  


我们有理由的认为在内存当中a的值被修改为3,但是结果呢? 我们来看一看




这不科学啊?? 我们再打开监视窗口看一下a的值.



我们都知道监视窗口看到的都是从内存当中拿到的,但是为什么内存当中为3,打印出来就是2呢? 我来解释一下.

C++编译器具有优化功能,当你定一个const的常量的时候,系统觉得它不会被改变了,于是做一个优化把该常量存到寄

存器当中,下次访问的过程更快速一点. 所以当显示窗口读取数据的时候,他会直接去寄存器当中读取数据.而不是去

内存,所以导致我们明明该掉了a的值,却打印不出来.

这个时候该我们的volatile出马了,往i前面加一个volatile之后就会解决这个问题,来看结果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值