深入理解C++中的Const,Mutable以及Volatile
我一直認為const表示一個常量,常量就是一個無法被修改的值,但是沒有深入理解const的實現,甚至不知道mutable和volatile的存在,最近在書中看到了這一部分的知識,所以本文將詳細解析這幾個關鍵詞。
首先考慮以下幾個問題:
1. const int a和int const a的區別。
2. const char* s和char *const s的區別。
3. 下列代碼有問題嗎?如果有問題應該如何修改?
class A { private: int a; const int fun() { a = 1; } int fun() const{ a = 2; } };
4. 下列代碼一定能達到目的嗎?為什麽?
//延時函數 void delayFun(unsigned int a) { while (a--) { } }
5.下列代碼運行結果是什麽?
const int i = 1; int* j = (int*)(&i); *j = 2; printf("%08x %d %08x %d", &i, i, j, *j);
針對上述問題解答:
1. 無區別,表示a是一個const int變量,a無法被修改,並且a可能編譯器優化掉(無內存地址)。
2. const char* s表示s是一個常量字符串的指針,它可以指向不同的常量字符串,例如
const char* s1 = "abc"; s1 = "xyz";但是字符串內容無法被修改,下列代碼出錯:s1[0]=‘c‘;char* const s表示一個字符串指針的常量。指向一個唯一的字符串指針,無法後續修改,下列代碼出錯:
char* const s1 = "abc"; s1 = "xyz";3. const int fun() 表示一個函數返回值是const int(事實上const int是無意義的),此函數和普通函數沒區別。int fun() const表示該函數是常量函數,此函數無法修改類中的成員變量(規定),如果一定要修改類中的成員變量,可以將該成員變量定義為mutable,如下:
class A { private: mutable int a; const int fun() { a = 1; } int fun() const { a = 2; } };4. 代碼可能會被優化掉,此函數是一個無效的循環,這類代碼會被編譯器優化掉,優化後就不存在延時效果了。如果一定要達到延時效果,可以將a定義為volatile。volatile表示此變量可能因為各種原因被修改,告訴編譯器不要優化此變量產生的代碼(這個一般是底層可能用到,硬件之類的,如果不理解volatile,可能導致代碼出現預料之外的情況)。
5. 這段代碼如果是debug模式下可能會被編譯器提示出錯,因為這裏采用了一個強制轉換修改了一個常量的值(編譯器的理解是,常量是無論如何都無法被修改的,所以高級一點的編譯器可能會對此代碼報錯),但是這段代碼從C語言的語言層面上來說是沒問題的,C語言裏可以將任意指針轉換為需要的指針。這段代碼在C++中輸出:
0075f8b4 1 0075f8b4 2輸出地址是一樣的,但是值不一樣。
為什麽會這樣呢?按理說地址一樣,他的值肯定也是一樣的,原因還是在與編譯器的優化(不是編譯器的錯,const就是一個常量,他就應該是無法被修改的,既然無法被修改,用常量替換沒問題)。編譯器將所有使用i的地方會用他的值替換,類似與C語言中的#define。這裏使用了強制轉換強制修改i所在內存的值,但是這個值變化了,不會修改編譯器優化後的代碼(優化後的代碼和和i這個符號都無關了),所以有上述輸出。如何修改呢?使用volatile,volatile會要求編譯器不要優化該常量,既然不會優化,那麽使用i的地方會使用i這個符號而不會優化為常量的值了。如下:
const volatile int i = 1; int* j = (int*)(&i); *j = 2; printf("%08x %d %08x %d", &i, i, j, *j);
可以這麽理解,const是一個C++為了替換C語言define而產生的關鍵字,const會留下一些坑。所以就使用mutable和volatile來填補這些坑。如果沒搞清const的這些問題,以後在開發過程中可能會碰到坑。
深入理解C++中的Const,Mutable以及Volatile