深入分析C++中幾個最不常用的關鍵字

來源:互聯網
上載者:User

mutable關鍵字
關鍵字mutable是C++中一個不常用的關鍵字,他只能用於類的非靜態和非常量資料成員
我們知道一個對象的狀態由該對象的非待用資料成員決定,所以隨著資料成員的改變,
對像的狀態也會隨之發生變化!
如果一個類的成員函數被聲明為const類型,表示該函數不會改變對象的狀態,也就是
該函數不會修改類的非待用資料成員.但是有些時候需要在該類函數中對類的資料成員
進行賦值.這個時候就需要用到mutable關鍵字了
例如: 複製代碼 代碼如下:class Demo
{
public:
Demo(){}
~Demo(){}
public:
bool getFlag() const
{
m_nAccess++;
return m_bFlag;
}
private:
int m_nAccess;
bool m_bFlag;
};
int main()
{
return 0;
}

編譯上面的代碼會出現 error C2166: l-value specifies const object的錯誤
說明在const類型的函數中改變了類的非待用資料成員.
這個時候需要使用mutable來修飾一下要在const成員函數中改變的非待用資料成員
m_nAccess,代碼如下:複製代碼 代碼如下:class Demo
{
public:
Demo(){}
~Demo(){}
public:
bool getFlag() const
{
m_nAccess++;
return m_bFlag;
}
private:
mutable int m_nAccess;
bool m_bFlag;
};
int main()
{
return 0;
}

這樣再重新編譯的時候就不會出現錯誤了!

volatile關鍵字
volatile是c/c++中一個鮮為人知的關鍵字,該關鍵字告訴編譯器不要持有變數的臨時拷貝,它可以適用於基礎類型
如:int,char,long......也適用於C的結構和C++的類。當對結構或者類對象使用volatile修飾的時候,結構或者
類的所有成員都會被視為volatile.
使用volatile並不會否定對CRITICAL_SECTION,Mutex,Event等同步對象的需要
例如:
int i;
i = i + 3;
無論如何,總是會有一小段時間,i會被放在一個寄存器中,因為算術運算只能在寄存器中進行。一般來說,volatitle
關鍵字適用於行與行之間,而不是放在行內。
我們先來實現一個簡單的函數,來觀察一下由編譯器產生出來的彙編代碼中的不足之處,並觀察volatile關鍵字如何修正這個不足之處。在這個函數體記憶體在一個busy loop(所謂busy loop也叫做busy waits,是一種高度浪費CPU時間的迴圈方法)複製代碼 代碼如下:void getKey(char* pch)
{
while (*pch == 0)

}

當你在VC開發環境中將最佳化選項都關閉之後,編譯這個程式,將獲得以下結果(彙編代碼)複製代碼 代碼如下:; while (*pch == 0)
$L27
; Load the address stored in pch
mov eax, DWORD PTR _pch$[ebp]
; Load the character into the EAX register
movsx eax, BYTE PTR [eax]
; Compare the value to zero
test eax, eax
; If not zero, exit loop
jne $L28

jmp $L27
$L28
;}

這段沒有最佳化的代碼不斷的載入適當的地址,載入地址中的內容,測試結果。效率相當的低,但是結果非常準確
現在我們再來看看將編譯器的所有最佳化選項開關都開啟以後,重新編譯器,產生的彙編代碼,和上面的代碼
比較一下有什麼不同複製代碼 代碼如下:;{
; Load the address stored in pch
mov eax, DWORD PTR _pch$[esp-4]
; Load the character into the AL register
movsx al, BYTE PTR [eax]
; while (*pch == 0)
; Compare the value in the AL register to zero
test al, al
; If still zero, try again
je SHORT $L84

;}

從代碼的長度就可以看出來,比沒有最佳化的情況要短的多。需要注意的是編譯器把MOV指令放到了迴圈之外。這在單線程中是一個非常好的最佳化,但是,在多線程應用程式中,如果另一個線程改變了變數的值,則迴圈永遠不會結束。被測試的值永遠被放在寄存器中,所以該段代碼在多線程的情況下,存在一個巨大的BUG。解決方案是重新寫一次getKey函數,並把參數pch聲明為volatile,代碼如下:複製代碼 代碼如下:void getKey(volatile char* pch)
{
while (*pch == 0)

}

這次的修改對於非最佳化的版本沒有任何影響,下面請看最佳化後的結果:複製代碼 代碼如下:;{
; Load the address stored in pch
mov eax, DWORD PTR _pch$[esp-4]
; while (*pch == 0)
$L84:
; Directly compare the value to zero
cmp BYTE PTR [eax], 0
; If still zero, try again
je SHORT $L84

;}

這次的修改結果比較完美,地址不會改變,所以地址聲明被移動到迴圈之外。地址內容是volatile,所以每迴圈之中它不斷的被重新檢查。
把一個const volatile變數作為參數傳遞給函數是合法的。如此的聲明意味著函數不能改變變數的值,但是變數的值卻可以被另一個線程在任何時間改變掉。

explicit關鍵字
我們在編寫應用程式的時候explicit關鍵字基本上是很少使用,它的作用是"禁止單參數建構函式"被用於自動型別轉換,其中比較典型的例子就是容器類型,在這種類型的建構函式中你可以將初始長度作為參數傳遞給建構函式.
例如:
你可以聲明這樣一個建構函式複製代碼 代碼如下:class Array
{
public:
explicit Array(int size);
......
};

在這裡explicit關鍵字起著至關重要的作用,如果沒有這個關鍵字的話,這個建構函式有能力將int轉換成Array.一旦這種
情況發生,你可以給Array支派一個整數值而不會引起任何的問題,比如:
Array arr;
...
arr = 40;
此時,C++的自動型別轉換會把40轉換成擁有40個元素的Array,並且指派給arr變數,這個結果根本就不是我們想要的結果.如果
我們將建構函式聲明為explicit,上面的賦值操作就會導致編譯器報錯,使我們可以及時發現錯誤.
需要注意的是:explicit同樣也能阻止"以賦值文法進行帶有轉型操作的初始化";
例如:複製代碼 代碼如下:Array arr(40);//正確
Array arr = 40;//錯誤
看一下以下兩種操作:
X x;
Y y(x);//顯式類型轉換
另一種
X x;
Y y = x;//隱式類型轉換

這兩種操作存在一個小小的差別,第一種方式式通過顯式類型轉換,根據型別x產生了型別Y的新對象;第二種方式通過隱式轉換產生了一個型別Y的新對象.
explicit關鍵字的應用主要就是上面所說的建構函式定義種,參考該關鍵字的應用可以看看STL原始碼,其中大量使用了該關鍵字

__based關鍵字
該關鍵字主要用來解決一些和共用記憶體有關的問題,它允許指標被定義為從某一點開始算的32位位移值,而不是記憶體種的絕對位置
舉個例子:複製代碼 代碼如下:typedef struct tagDEMOSTRUCT {
int a;
char sz[10];
} DEMOSTRUCT, * PDEMOSTRUCT;
HANDLE hFileMapping = CreateFileMapping(...);
LPVOID lpShare = (LPDWORD)MapViewOfFile(...);
DEMOSTRUCT __based(lpShare)* lpDemo;

上面的例子聲明了一個指標lpDemo,內部儲存的是從lpShare開始的位移值,也就是lpHead是以lpShare為基準的位移值.
上面的例子種的DEMOSTRUCT只是隨便定義的一個結構,用來代表任意的結構.
雖然__based指標使用起來非常容易,但是,你必須在效率上付出一定的代價.每當你用__based指標處理資料,CPU都必須為它加上基地址,才能指向真正的位置.

在這裡我只是介紹了幾個並不時很常見的關鍵字的意義即用法,其他那些常見的關鍵字介紹他們的文章已經不少了在這裡
就不再一一介紹了.希望這些內容能對大家有一定的協助!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.