C++——關鍵字const

前景小故事

??最近重溫《C++ Primer》時被一位朋友看見。也許因為這位朋友太閑了策泣,他強行湊過來要與我討論一些零零散散的C++內容,其中就有這篇文章的主角——C++中的const關鍵字抬吟。
??起初我內心是拒絕的:const是什么值得討論的東西嗎萨咕?不過最后我還是被他的熱情打敗,一番交流后得出了下面的內容火本。
(希望有緣點進來看到這里的讀者可以花一點時間看正文內容并給筆者一些反饋任洞,這是筆者第一次發(fā)布文章,需要各位的建議讓以后的文章比現(xiàn)在的能看)

正題

??在C++中发侵,const絕大多數地出現(xiàn)是為了作為限制符限制變量的行為。被const修飾的變量稱為常量(總覺得這句話有語病)妆偏,最集中的一點體現(xiàn)是:常量需要在定義時初始化刃鳄,至于是否必須顯式初始化這個問題,筆者本機g++測試的結果是:內置類型(如int)在函數體外定義(此時內置類型會被默認初始化)會被編譯器報錯钱骂,而自定義的數據結構(擁有默認構造函數)則可以被編譯通過叔锐。這個問題筆者認為不必深究,在使用常量時都用顯式初始化即可见秽,因為實在是想像不到常量使用默認初始化的必要情況愉烙。
??最簡單的常量定義(以內置類型int為例)如下:

const int ivar = 777;

??定義后,ivar將在其生命周期內永遠地(如果沒有什么意外的話)作為777的代言解取,編譯器會檢測在ivar生命周期內對其所代表的內存進行非法改動的行為步责。試圖對它直接賦值的語句將會被報錯:

ivar = 888; 
//error: cannot assign to variable 'ivar' with const-qualified type 'const int'

??對于const的用處,最常被擺上臺面的例子之一是:定義一個名為buf_size的常量用于表示需要定義的緩沖區(qū)大匈骺唷:

const size_t buf_size = 1024;
/* 其他代碼 */
//緩沖區(qū)定義
char *buf[buf_size] = {0};

??之后對緩沖區(qū)的操作如果出現(xiàn)需要使用緩沖區(qū)大小這一信息的情況時可以直接使用buf_size常量蔓肯,保證需要修改緩沖區(qū)大小時不需要修改多個地方。人們稱以上技巧為非硬編碼振乏。

與預處理變量的區(qū)別

朋友的朋友指出蔗包,C++11中有用于定義常量表達式的關鍵字constexpr,不僅完全替代了預處理變量的功能慧邮,還比后者更安全调限,所以宏定義永遠不再應該被用來定義預處理變量了,故以下內容僅作了解误澳。

??在C語言中經常能看見大量的宏定義耻矮。宏定義經常會被用來定義一些預處理變量,如:

#define BUF_SIZE 1024

??源程序添加以上語句后忆谓,在編譯前的預處理階段該語句以下的BUF_SIZE都被替換為1024淘钟。比如:

//預處理前源程序
char *buf[BUF_SIZE] = {0};
//預處理后等價于
char *buf[1024] = {0};

??C++繼承了C語言的預處理機制,也就是說C++也可以使用宏定義定義預處理變量。在C++11前米母,為了表示空指針經常會使用到定義在<cstdlib>中的NULL正是預處理變量勾扭。
??如上面說的,宏定義參與的是編譯前的預處理過程铁瞒,看起來與文本替換有點相似妙色。于是預處理變量與const修飾的變量最大差別出現(xiàn)了:聚焦上面的例子,預處理變量BUF_SIZE在編譯前完成了替換的工作慧耍,到了編譯階段編譯器根本不知道1024曾經是一個預處理變量而把它當作一個字面值處理身辨;而const修飾的變量buf_size是會參與編譯過程并分配到作為變量應有的內存的。拋開繁瑣的細節(jié)簡單地說:預處理變量參與預處理過程而const修飾的變量參與編譯過程芍碧;預處理變量并不是真正意義上的變量而const修飾的變量是煌珊。
??根據上面的總結,預處理變量似乎比const修飾的變量好用:沒有多余定義變量的指令泌豆。想下定論前筆者認為還有兩點需要考慮到:首先是前者僅是一個替換的過程定庵,比起有指定類型且參與編譯過程的后者可能會有著更多的安全問題;如果常量不是簡單的內置類型(如字符串)且在多處被使用踪危,前者每次都需要申請臨時空間而后者只需要申請一次即可蔬浙。
??筆者的見解是,在所需常量為內置類型且有足夠把握不會出現(xiàn)安全問題的情況下使用預處理變量贞远,而其他情況使用const修飾的變量比較好畴博;甚至如果閑麻煩可以全部都使用后者。

術語解釋:頂層const與底層const

??按照《C++Primer》里的說法蓝仲,頂層const(top-level const)指變量本身是不可改變的俱病,前文例子中buf_size即是頂層const;而底層const(low-level const)與以指針為代表的復合類型所指向的值有關袱结,如:

const int *pi = &ivar;

??此時可以說pi是底層const庶艾。

指針與const

??以下通過例子列舉了const在指針中的使用:

const int cval = 7;
int val = 777, val2 = 7777;
const int *pi1 = &cval;       //pi1是一個指向int常量的指針,且確實指向了常量
const int *pi2 = &val;        //pi2是一個指向int常量的指針擎勘,但其實指向的并不是常量
*pi1 = 9;                      //錯誤咱揍,不允許更改指向了const的指針所指向的值
pi1 = &val;                    //正確,允許更改pi1的指向
*pi2 = 888;                  //錯誤棚饵,不允許更改指向了const的指針所指向的值
int *const pi3 = &cval;       //錯誤:pi3是一個指向int的常量指針煤裙,但卻指向了常量
int *const pi4 = &val;    //pi4是一個指向int的常量指針,且確實指向了int變量
pi4 = &val2;                //錯誤噪漾,不允許更改常量指針的指向
*pi4 = 999;                //正確硼砰,允許更改指向非const的指針所指向的值
const int *const pi5 = &cval; //pi5是一個指向int常量的常量指針

??通過上面可以看出,本身是常量時欣硼,指針不允許修改自身的指向题翰;而當所指向的值類型被const所修飾時,不能修改指針所指向的值。前者即為頂層const的含義豹障,后者為底層const的含義冯事。最后一個例子指出指針可以同時是頂層const以及底層const。

引用與const

??引用在普通情況是不可以與字面值血公、表達式等綁定的昵仅,但如果引用加上const后就可以達到這一目的了。下面是const引用的一些例子:

int i = 7;
const int ci = 7;
const int &ival1 = i;          //ival1綁定了一個int變量累魔,但不能通過ival改變i的值
const int &ival2 = ci;        //ival2綁定了一個int常量
const int &ival3 = 777;    //ival3綁定了一個字面值
const int &ival4 = ci + 1; //ival4綁定了一個表達式
int &ival5 = 777;            //錯誤摔笤,引用不能綁定字面值
int &ival6 = 777;            //錯誤,引用不能綁定表達式

??上述例子ival1垦写、ival2的情況都是可以預見的吕世,至于ival3與ival4是因為編譯器會將其做如下變換(ival3為例):

const int temp = 777;
const int &ival3 = temp;

??也就是說,最終ival3綁定的是一個存放了777的臨時變量梯投。
??由于頂層const是針對變量而言的命辖,所以不能被稱為變量的引用并不存在頂層const。
??上面的例子也表明了晚伙,無論是指針也好引用也好,身為底層const時它們會認為與之綁定或其指向的變量為頂層const俭茧,所以對變量的值進行修改是非法的咆疗。而實際上那個變量并沒有一定被const修飾,只是它們自以為的罷了母债。

??以上就是我們討論的const的內容了午磁。事實上const還有其他用處和比較特殊的用法在這里并沒有提到,主要還是對變量定義的const作用展開了一些討論和記錄毡们。如果有機會其他的用法會穿插在其他的C++討論中迅皇。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市衙熔,隨后出現(xiàn)的幾起案子登颓,更是在濱河造成了極大的恐慌,老刑警劉巖红氯,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件框咙,死亡現(xiàn)場離奇詭異,居然都是意外死亡痢甘,警方通過查閱死者的電腦和手機喇嘱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來塞栅,“玉大人者铜,你說我怎么就攤上這事。” “怎么了作烟?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵愉粤,是天一觀的道長。 經常有香客問我俗壹,道長科汗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任绷雏,我火速辦了婚禮头滔,結果婚禮上,老公的妹妹穿的比我還像新娘涎显。我一直安慰自己坤检,他們只是感情好,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布期吓。 她就那樣靜靜地躺著早歇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讨勤。 梳的紋絲不亂的頭發(fā)上箭跳,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天,我揣著相機與錄音潭千,去河邊找鬼谱姓。 笑死,一個胖子當著我的面吹牛刨晴,可吹牛的內容都是我干的屉来。 我是一名探鬼主播,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼狈癞,長吁一口氣:“原來是場噩夢啊……” “哼茄靠!你這毒婦竟也來了?” 一聲冷哼從身側響起蝶桶,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤慨绳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后真竖,有當地人在樹林里發(fā)現(xiàn)了一具尸體儡蔓,經...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年疼邀,在試婚紗的時候發(fā)現(xiàn)自己被綠了喂江。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡旁振,死狀恐怖获询,靈堂內的尸體忽然破棺而出涨岁,到底是詐尸還是另有隱情,我是刑警寧澤吉嚣,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布梢薪,位于F島的核電站,受9級特大地震影響尝哆,放射性物質發(fā)生泄漏秉撇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一秋泄、第九天 我趴在偏房一處隱蔽的房頂上張望琐馆。 院中可真熱鬧,春花似錦恒序、人聲如沸瘦麸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滋饲。三九已至,卻和暖如春喊巍,著一層夾襖步出監(jiān)牢的瞬間屠缭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工崭参, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留呵曹,地道東北人。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓阵翎,卻偏偏與公主長得像逢并,于是被迫代替她去往敵國和親之剧。 傳聞我的和親對象是個殘疾皇子郭卫,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內容