const_cast的使用:添加或去掉const、常量折叠
避免未定義行為(使用引用時的未定義行為)
一個變量在使用const_cast去掉指針或者引用的const限定符后,“如果常量本身不是常量,獲得的權限是合法的, 如果本身是常量,使用const_cast再寫的后果是未定義的。”
int main(){
?? ?const int a = 1;
?? ?int & b = const_cast<int&>(a);
?? ?b = 2;
?? ?cout << a ;
?? ?cout << b;
}
1
2
3
4
5
6
7
雖然上面程序運行沒有問題,但定義const常量的初衷肯定就是為了不修改,所以出現了上述情況肯定是程序設計有問題。
而且你會發現調試窗口中,兩個變量的值按照我們所想,但打印時,卻是先打印1,后打印2。這是因為常量折疊。
常量折疊
將上面代碼進行反匯編。
?? ?const int a = 1;
00971F72 C7 45 F4 01 00 00 00 mov ? ? ? ? dword ptr [a],1 ?
?? ?int & b = const_cast<int&>(a);
00971F79 8D 45 F4 ? ? ? ? ? ? lea ? ? ? ? eax,[a] ? ? //可以發現,引用本質是指針,這里把a的地址先存到eax
00971F7C 89 45 E8 ? ? ? ? ? ? mov ? ? ? ? dword ptr [b],eax ? //再把地址賦值給b
?? ?b = 2;
00971F7F 8B 45 E8 ? ? ? ? ? ? mov ? ? ? ? eax,dword ptr [b] ?//先把地址給eax
00971F82 C7 00 02 00 00 00 ? ?mov ? ? ? ? dword ptr [eax],2 ? ?//中括號里面放的是地址
?? ?cout << a ;
00971F88 8B F4 ? ? ? ? ? ? ? ?mov ? ? ? ? esi,esp ?
00971F8A 6A 01 ? ? ? ? ? ? ? ?push ? ? ? ?1 ? ? ?//打印的時候,直接入棧的是1,這里發生了常量折疊
00971F8C 8B 0D D4 D0 97 00 ? ?mov ? ? ? ? ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (097D0D4h)] ?
00971F92 FF 15 E4 D0 97 00 ? ?call ? ? ? ?dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (097D0E4h)] ?
00971F98 3B F4 ? ? ? ? ? ? ? ?cmp ? ? ? ? esi,esp ?
00971F9A E8 0E F3 FF FF ? ? ? call ? ? ? ?__RTC_CheckEsp (09712ADh) ?
?? ?cout << b;
00971F9F 8B F4 ? ? ? ? ? ? ? ?mov ? ? ? ? esi,esp ?
00971FA1 8B 45 E8 ? ? ? ? ? ? mov ? ? ? ? eax,dword ptr [b] ?
00971FA4 8B 08 ? ? ? ? ? ? ? ?mov ? ? ? ? ecx,dword ptr [eax] ?
00971FA6 51 ? ? ? ? ? ? ? ? ? push ? ? ? ?ecx ?
00971FA7 8B 0D D4 D0 97 00 ? ?mov ? ? ? ? ecx,dword ptr [_imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A (097D0D4h)] ?
00971FAD FF 15 E4 D0 97 00 ? ?call ? ? ? ?dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (097D0E4h)] ?
00971FB3 3B F4 ? ? ? ? ? ? ? ?cmp ? ? ? ? esi,esp ?
00971FB5 E8 F3 F2 FF FF ? ? ? call ? ? ? ?__RTC_CheckEsp (09712ADh)?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
常量折疊就是,在編譯階段,對該變量進行值替換。類似宏定義。
使用指針時的未定義行為
int main(){
?? ?const int a = 1;
?? ?int * b = const_cast<int*>(&a);
?? ?*b = 2;
?? ?cout << &a <<endl;
?? ?cout << b << endl;
?? ?cout << a << endl;
?? ?cout << *b << endl;
}
1
2
3
4
5
6
7
8
9
使用const_cast去掉const限定符
只有當對象原本就是非常量時,才是正確的行為。
void func(const int& a)//形參為,引用指向const int
{
?? ?int& b = const_cast<int&>(a);//去掉const限定,因為原本為非常量
?? ?b++;
?? ?return;
}
int main()
{
?? ?int a = 100;
?? ?func(a);
?? ?cout << a << endl; ?// 打印101
?? ?return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
此函數的形參本來設置為int& a就好,但這里只是為了體現用法。
使用const_cast添加const限定符
const string& shorter(const string& s1, const string& s2) {
?? ?return s1.size() <= s2.size() ? s1 : s2;
}
string& shorter(string& s1, string& s2) {
?? ?//重載調用到上一個函數,它已經寫好了比較的邏輯
?? ?auto &r = shorter(const_cast<const string&>(s1), const_cast<const string&>(s2));
?? ?//auto等號右邊為引用,類型會忽略掉引用
?? ?return const_cast<string&>(r);
}
1
2
3
4
5
6
7
8
9
10
const string&版本函數為比較字符串長度的正確實現,因為比較長度時不會改變字符串,所以參數和返回值都為const。
當實參為const時,由于函數重載,會調用到const string&版本函數,這也是期望的結果。
但當實參為非const時,我們希望還是繼續調用已經寫好比較邏輯的const string&版本函數,但返回值希望返回string &,所以這里再封裝一層函數。(這里一個知識點,函數重載是忽略返回值,且忽略形參的頂層const,可以這么理解,有頂層const的概念,說明參數是引用或指針,但我們主要關心的是指向的數據,所以要忽略頂層const)(因為參數忽略頂層const,所以重載時只關心底層const是否一樣)
————————————————
版權聲明:本文為CSDN博主「anlian523」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/anlian523/article/details/95751762
總結
以上是生活随笔為你收集整理的const_cast的使用:添加或去掉const、常量折叠的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编译器在处理const变量跟一般变量时的
- 下一篇: string’ does not nam