自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文講清C/C++ Const/Const_Cast/Constexpr

開(kāi)發(fā) 后端
很多人搞不清const、const_cast、constexpr的用法,稀里糊涂地用。一般而言,即使亂用,問(wèn)題也不大,因?yàn)殄e(cuò)大發(fā)了會(huì)崩,崩了自然會(huì)被修正,不崩自然也就沒(méi)事。

[[422168]]

本文轉(zhuǎn)載自微信公眾號(hào)「碼磚雜役」,作者我不想種地 。轉(zhuǎn)載本文請(qǐng)聯(lián)系碼磚雜役公眾號(hào)。

很多人搞不清const、const_cast、constexpr的用法,稀里糊涂地用。一般而言,即使亂用,問(wèn)題也不大,因?yàn)殄e(cuò)大發(fā)了會(huì)崩,崩了自然會(huì)被修正,不崩自然也就沒(méi)事。但作為一個(gè)有追求的專(zhuān)業(yè)程序員,自當(dāng)聞過(guò)則喜,搞清楚弄明白。

一、const

C語(yǔ)言的const用法

先講const,這玩意兒怎么翻譯我也拿不準(zhǔn),C語(yǔ)言中該關(guān)鍵字的用法比較簡(jiǎn)單,大概有如下幾種用法:

[1] 修飾普通變量:變量只讀,在程序運(yùn)行過(guò)程中不可修改。

  1. const int i = 100; //i is read only 
  2. i = 200; //compile error, variable i can not assignable 

[2] 修飾指針 const T* p:表示不能通過(guò)p去修改p指向?qū)ο蟮膬?nèi)容,另一方面只能通過(guò)p調(diào)用T類(lèi)的const成員函數(shù)

  1. const struct Foo *f = new Foo;  
  2. f->dataX = 100; //compile error 
  3.  
  4. const char* p = "abc";  
  5. p[1] = 'x'; //compile error 
  6. f->nonconst_member_function(); ///compile error (后面再講) 

[3] 修飾指針 T* const p:表示指針只能在初始化時(shí)設(shè)置指向,之后便不能修改指向。

  1. char s1[] = "abc";  
  2. char s2[] = "xyz"
  3. char* const p = s1; 
  4. p = s2; //compile error 

[4] 修飾指針 const T* const p:表示既不能通過(guò)p修改它指向的對(duì)象,又不能更改p的指向。

  1. const char* const p = "abc"
  2. p[1] = 'B'; //compile error 
  3. p = "xyz"; //compile error 

[5] 修飾函數(shù)參數(shù):c語(yǔ)言中const修飾參數(shù)反映的含義同上所述

小結(jié):C語(yǔ)言中,const的用法差不多就這些,比較簡(jiǎn)單。

C++擴(kuò)充了const的用法

[1] 修飾成員變量:const成員變量只能在初始化列表里做初始化,程序運(yùn)行中不可修改;如果是const整型,則可以C++11標(biāo)準(zhǔn)之后直接初始化。

  1. struct Foo  
  2.     Foo() : PI(3.15) {} // PI is initialized by initializer list 
  3.     const int c = 100; //C++11 support 
  4.     const float PI; 
  5. }; 

[2] 修飾成員函數(shù):表示該成員函數(shù)是只讀函數(shù),不會(huì)修改默認(rèn)參數(shù)this的成員變量,如果修改會(huì)編譯報(bào)錯(cuò)。

  1. class Foo 
  2.     int m_money; 
  3. public
  4.     int get_money() const //✅ 
  5.     { 
  6.         return m_money; 
  7.     } 
  8.  
  9.     int set_money(int money) const //❌ 
  10.     { 
  11.         m_money = money; //修改了this->m_money;需去掉函數(shù)const修飾 
  12.     }     
  13. }; 

[3] 修飾引用:引用是C++才有的語(yǔ)法特征,引用是別名,本質(zhì)上跟指針差不多,所以const修飾引用跟修飾指針的語(yǔ)義和約束差不多。

  1. Foo f; 
  2. const Foo& r = f; 
  3. r.m_data = 1; //compile error 

[4] C++中對(duì)const修飾指針的補(bǔ)充

  1. struct Foo  
  2.   int const_member_function() const { return m_data; } 
  3.   int non_const_member_function(int data) { m_data = data; } 
  4.   int m_data; 
  5. }; 
  6.  
  7. int main() 
  8.   const Foo* f = new Foo; 
  9.   f->const_member_function();  //OK 
  10.   f->non_const_member_function(); //compile ERROR 
  11.   return 0; 

為什么呢?因?yàn)閏onst成員函數(shù)相當(dāng)于承諾不會(huì)修改this的成員變量,而該承諾會(huì)被編譯器檢查,如果沒(méi)有履行承諾,則編譯器會(huì)報(bào)錯(cuò)。而const Foo* f意味著不能通過(guò)f去修改f指針指向變量的內(nèi)部值。

通過(guò)f->data = 1的方式肯定是不行。

另一方面,你只能通過(guò)f去調(diào)用它的const成員函數(shù),因?yàn)閏onst成員函數(shù)的語(yǔ)義就是不會(huì)修改this的值,編譯器很容易執(zhí)行這個(gè)校驗(yàn)。

const修飾參數(shù)

const可以修飾普通參數(shù),也可以修飾指針/引用參數(shù),因?yàn)樾螀⑹菍?shí)參的副本,所以const修飾普通參數(shù)其實(shí)沒(méi)什么意義,我們著重講講const修飾指針/引用參數(shù)。

比如標(biāo)準(zhǔn)C庫(kù)函數(shù)strcpy的簽名:char *strcpy(char * dst, const char * src);

dst表示目標(biāo)地址,src表示源串,const修飾了源串,這是因?yàn)閺脑创截惖侥繕?biāo)串,不需要修改源串內(nèi)容,這相當(dāng)于向strcpy調(diào)用者承諾:

放心大膽的調(diào)用吧,strcpy函數(shù)實(shí)現(xiàn)保證不會(huì)修改src的內(nèi)容,編譯器會(huì)執(zhí)行這種檢查。

這樣,在review代碼的時(shí)候,如果想追蹤src在哪里被修改了,當(dāng)看到strcpy的簽名,就不用打開(kāi)函數(shù)去看實(shí)現(xiàn),只要不違背承諾,肯定不是這個(gè)函數(shù)內(nèi)改動(dòng)了src。

const char *src是一種承諾,也是一種約束。調(diào)用的地方,const char*形式的形參,既傳const char*實(shí)參,也可以傳char*實(shí)參,因?yàn)閰?shù)const char*是更強(qiáng)的承諾。

但反之不成立。比如第一個(gè)參數(shù)dst是不帶const的,那么如果有一個(gè)變量類(lèi)型為const char* p,那不能把p作為第一個(gè)參數(shù)傳遞進(jìn)strcpy,編譯不過(guò)。

因?yàn)閟trcpy不承諾不修改dst,是一個(gè)更弱的承諾,只有聲明為const指針的參數(shù),才能傳遞const指針實(shí)參。

const其他

const還可以修飾返回值,還可以跟extern結(jié)合,但這些都是一些小語(yǔ)法技巧,一般開(kāi)發(fā)用不太到,真碰到再查不遲。

二、const_cast

const_cast有什么用?

const是C++的一個(gè)強(qiáng)制轉(zhuǎn)換,它用來(lái)去掉const屬性,比如:

  1. Foo foo; 
  2. const Foo *f1 = &foo; 
  3. Foo* f2 = const_cast<Foo*>(f); 
  4. Foo* f3 = (Foo*)f; 

const_cast的作用跟強(qiáng)轉(zhuǎn)差不多,C++加const_cast主要是為了功能完整性,const_cast作用于引用跟作用于指針差不多。

為什么說(shuō)const_cast幾乎都反應(yīng)接口設(shè)計(jì)有問(wèn)題

程序設(shè)計(jì)要言行一致,遵守承諾,這意味著:不應(yīng)該把參數(shù)聲明為const指針,而函數(shù)實(shí)現(xiàn)里借助強(qiáng)制去掉const屬性。

首先,這樣做是危險(xiǎn)的,比如const char* p = "abc"; p指向常量字符串被作為參數(shù)傳遞,被強(qiáng)轉(zhuǎn)+修改,則會(huì)導(dǎo)致程序crash。

其次,這樣做是分裂的,因?yàn)槟慵觕onst修飾相當(dāng)于讓編譯器幫你執(zhí)行檢查,以便在你違背承諾的時(shí)候通過(guò)編譯期檢查報(bào)錯(cuò)提醒你,但在它真正向你報(bào)錯(cuò)的時(shí)候,你又說(shuō)別管啦,老子就是要蠻干。

const_cast或者通過(guò)c風(fēng)格強(qiáng)轉(zhuǎn),基本上都暴露出設(shè)計(jì)上的問(wèn)題。

設(shè)計(jì)良好的程序基本上不需要const強(qiáng)轉(zhuǎn)。因?yàn)閏onst約束在調(diào)用鏈會(huì)傳播,所以,你需要一以貫之的遵守約定,找到導(dǎo)致需要const強(qiáng)轉(zhuǎn)的錯(cuò)誤源頭,這可能會(huì)多費(fèi)一點(diǎn)時(shí)間,但它是值得的。

三、constexpr

const沒(méi)有區(qū)分編譯期常量和運(yùn)行期常量,constexpr是C++11開(kāi)始提出的關(guān)鍵字,被限定為編譯器常量,其意義與14版本有一些區(qū)別。

C++11中的constexpr指定的函數(shù)返回值和參數(shù)必須要保證是字面值,而且必須有且只有一行return代碼,這給函數(shù)的設(shè)計(jì)者帶來(lái)了更多的限制,比如通常只能通過(guò)return 三目運(yùn)算符+遞歸來(lái)計(jì)算返回的字面值。

而C++14中只要保證返回值和參數(shù)是字面值就行了,函數(shù)體中可以加入更多的語(yǔ)句,方便了更靈活的計(jì)算。

這里我們主要講constexpr和const的區(qū)別。

constexpr可以用來(lái)修飾變量、函數(shù)、構(gòu)造函數(shù)。一旦以上任何元素被constexpr修飾,那么等于說(shuō)是告訴編譯器 “請(qǐng)大膽地將我看成編譯時(shí)就能得出常量值的表達(dá)式去優(yōu)化我”。

  1. constexpr func()  
  2.   return 10; 
  3.  
  4. int main() 
  5.   int arr[func()]; 

編譯期大膽地將func()做了優(yōu)化,在編譯期就確定了func計(jì)算出的值10而無(wú)需等到運(yùn)行時(shí)再去計(jì)算。

這就是constexpr的第一個(gè)作用:給編譯器足夠的信心在編譯期去做被constexpr修飾的表達(dá)式的優(yōu)化。

constexpr還有另外一個(gè)特性,雖然它本身的作用之一就是希望程序員能給編譯器做優(yōu)化的信心,但它卻猜到了自己可能會(huì)被程序員欺騙,而編譯器并不會(huì)對(duì)此“惱羞成怒”中止編譯。

四、結(jié)論

C/C++程序應(yīng)該積極的使用const/constexpr,什么叫積極使用?只要有可能,那么我們就應(yīng)該用const/constexpr。

只要可能就應(yīng)該用xx,這種話(huà)一般而言都是錯(cuò)的,但用在const/constexpr卻很正確,因?yàn)槭褂胏onst/constexpr基本上都會(huì)讓你的程序更健壯、更快,const修飾的整型變量,在gcc開(kāi)優(yōu)化選項(xiàng)的時(shí)候,有可能被直接編譯到匯編代碼指令,而非生成一個(gè)變量,而constexpr的優(yōu)化作用在前面一節(jié)已經(jīng)闡述。

與之對(duì)應(yīng)的是:只要有可能,就不要使用const_cast,它基本上都反映了接口設(shè)計(jì)上的問(wèn)題。

 

就醬,信不信隨你!

 

責(zé)任編輯:武曉燕 來(lái)源: 碼磚雜役
相關(guān)推薦

2011-07-20 10:06:54

CC++const

2024-03-11 15:32:50

C++開(kāi)發(fā)

2010-02-02 14:06:50

C++ const變量

2011-06-21 10:44:31

const

2011-06-21 10:37:56

const

2023-09-26 22:37:16

C++const

2024-02-23 18:04:37

C++const關(guān)鍵字

2009-08-26 17:31:59

C# const常量

2020-10-26 09:18:50

RedisCluste

2011-07-20 16:57:05

C++const

2021-07-28 06:53:02

C++Const指針傳遞

2011-07-14 09:09:14

const

2009-08-27 15:17:40

C# const變量

2024-08-06 16:28:57

2024-08-16 09:06:03

2021-01-27 09:34:51

Visual C++Dev C++codelite

2009-08-27 10:54:09

C# const和st

2021-09-09 17:05:36

C++智能指針語(yǔ)言

2019-09-16 12:00:03

constC編程語(yǔ)言

2023-12-01 13:47:45

C語(yǔ)言conststat
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)