C++—const volatile mutable的用法
const volatile mutable的用法
_______________________________________________
相信const大家對他並不陌生,可能大家在日常的編寫代碼當中就會時常用到const,但是剩下的兩個關鍵字不知道我們有
沒有使用過volatile和mutable兩個關鍵字其實不算特別常用,但是我們一定要知道這個關鍵字有什麼用,應該怎麼用.首
先const的基本操作我曾經寫過一篇博客: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[]()const當中調用但是你還說重複了一些代碼比如兩次return語句,函數調用.真正該做
的是實現operator[]的機能一次並使用它兩次。也就是你只需要寫一個函數,令另外一個調用這個,這促使我們將
常量性轉移. 接下來 見證奇蹟我們來看看下面這個代碼是怎麼實現的上述的操作的:
class TextBlock
{
public:
...
constchar& operator[](std::size_t position) const
{
...
...
...
return text[position];
}
constchar& operator[](std::size_t position)
{
returnconst_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修飾的函數裡面的所有值都不能修改.
代碼舉例:
[cpp] view plain copy
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:
mutableint 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(volatileint *ptr)
{
return *ptr * *ptr;
}
這個程序有什麼問題嗎? 如果我們不去關心volatile關鍵字的話,那麼這個程序你怎麼看都會覺得沒多大問題.但是這裡
面問題大這ne, 首先參數聲明為volatile就是表明*ptr可能會隨時改變.上述代碼運行時,編譯器可能產生這樣的代碼:
[cpp] view plain copy
int square(volatileint *ptr)
{
int a,b;
a = *ptr;
b = *ptr;
return a * b;
}
因為你的*ptr是隨時都可以意想不到的變化,所以有可能a*b的時候,a b的值不相同. 這樣你就得到一個錯誤的結果
改正後的程序:
[cpp] view plain copy
int square(volatileint *ptr)
{
int a;
a = *ptr;
return a * a;
}
第二個問題,看如下代碼:
#include<iostream>
#include<Windows.h>
#include<assert.h>
usingnamespace std;
int main()
{
constint 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之後就會解決這個問題,來看結果:
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
※騰訊雲DevOps流水線的應用與實踐
※前方高能提示:SDCC 2017之區塊鏈技術實戰線上峰會開播倒計時
※html 使用 gka 加速 createjs 動畫開發及圖片優化
※Chrome 搜索 User-Agent Switcher 排行第一的插件竟是木馬
※三分鐘讀懂TT貓分散式、微服務和集群之路
TAG:青峰科技 |