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修飾,代表這個對象體現常量語義,但同時可能被當前對象所在程序上下文意外的狀況修改。
相關文章
相關標籤/搜索