你不知道的c 11

2022-05-11 04:00:31 字數 4457 閱讀 9175

隨著c++11的發布,c++這門語言有了本質上的提公升。c++14,c++17的相繼推出,更是讓c++這門語言達到了乙個新高度。新的標準庫設施,新的語法,讓我們得以書寫更加安全、便捷、高效的程式。

2023年6月程式語言排行榜:

那麼這些新的語法究竟是什麼?它們如何使用?能為我們程式設計帶來哪些便利?這便是本文所**的。

新的空指標型別——nullptr

適用度:★★★★★

nullptr是一種特殊的字面值,它可以轉化為任意一種指標型別。 原來我們初始化乙個空指標都是直接將他賦值為null,但null實際上是乙個巨集,其值相當於0。

編譯器是這麼定義null的:

#ifdef __cplusplus //如果定義__cplusplus巨集,說明正在編譯c++語言

#define null 0

#else

#define null ((void *)0)

#endif

也許你會想「我們用null還不是照樣吊打集訓隊」,nullptr好像並沒有什麼用。

考慮這樣一段**:

int f(int x)

int f(int *x)

int main()

很顯然,編譯失敗,對f的呼叫有二義性。因為null相當於0,既可轉化為指標,也可轉化為整形。將null換做nullptr即可,nullptr便是為了解決這種二義性的問題而誕生的。

條件允許的前提下,盡量使用nullptr,它比null更加安全, 原來這樣寫:

int a = null;

int *b = null;

現在應該這樣寫:

int a = null;

int *b = nullptr;

避免奇葩錯誤——constexpr變數

適用度:★★★★☆

在程式設計中,我們經常遇到需要定義常量的情況,但有些常量卻並不是你所想的「常量」。因而會引發一些意想不到的錯誤。

例如:int a;

const int b = a + 10;

int c[b];//錯誤,b不是乙個常量表示式,它的值每次執行都有可能不一樣。

b的確是**乙個常量——它的值在程式的執行期間不會被修改**,但是**它並不是常量表示式——每次執行程式時都為同乙個值,且程式執行期間無法被修改。**

使用**constexpr**而非const來宣告常量,讓編譯器來幫你檢查常量是不是每次程式執行都為同乙個值。

int a;

constexpr b = a + 10;//錯誤!a不是常量表示式!

int a;

const int b = a + 10;

constexpr int c = b + 10;//錯誤,b為常量,但不是常量表示式!

const int a = 10;

const int b = a + 10;

constexpr int c = b + 10;//正確

省事好幫手——auto型別指示符

適用度:★★★★★

有些型別名字太長,難以拼寫,浪費時間。怎麼辦?

知道函式的作用,卻無法拼寫其返回型別,無法儲存其返回值。怎麼辦?

這個時候auto型別指示符就能夠助我們一臂之力了。

原來我們這麼寫:

vectorvec;

for(vector::iterator it = vec.begin();it != vec.end();it++)//do something

現在可以簡單的這麼寫:

vectorvec;

for(auto it = vec.begin();it != vec.end();it++)//do something

怎麼樣?程式瞬間清爽了許多有木有。而且還可以節約大量寶貴的時間

因為編譯器是依靠初始值來推斷auto變數的型別的,所以auto變數必須要有初始值。

即使是這樣也不行:

auto a;

a = 10;

當然,也不能用auto來定義陣列

auto和引用一起會產生一些奇怪的問題:

int i = 1,&r = i;//定義變數i,r為i的引用

auto p = r;//沒錯,p的值為int,其值為1

為什麼?因為引用即別名。正如我們熟知的,使用引用其實是使用引用的物件,特別當引用被用作初始值的時候,真正參與初始化的其實是引用物件的值。此時編譯器以引用物件的型別作為auto的型別。

自動型別推斷——decltype型別指示符

適用度:★★★★☆

上文提到了auto的用法,有時候我們想要用表示式的型別初始化乙個變數,卻並不想用表示式的值初始化這個變數。這個時候decltype型別指示符就可以派上用場了。

劇透:下文位置返回型別配合decltype型別指示符有驚喜

我們可以這樣用decltype型別指示符來定義變數:

int a = 10;

decltype(a) b;

b = 20;

但是要注意,decltype只會用表示式的返回值進行推斷,並不會執行表示式。例如:

int f()

decltype(f()) i = 123;//i的值為123

//程式執行並不會有任何輸出,因為f函式並沒有實際執行。

int i = 1;

decltype(i = 123) b = i;

cout << i << endl;//輸出1,因為i = 42表示式並未實際執行

decltype和auto都可以完成型別推斷的任務,那麼它們有什麼不同呢?

1.處理引用

int i = 1,&r = i;//定義int型變數i,r為i的引用。

auto a = r;//此時a的型別為int

decltype(r) b = r;//此時b的型別為int&,即為int的引用。

2.處理頂層const

這裡引入乙個概念:

1.底層const,物件所指向的物件是const的。 2.頂層const,物件本身是const的。

auto會忽略掉頂層const和引用,但是會保留底層const。

const int ci = i,&cr = ci;

auto a = ci;//a為int,頂層const被忽略

auto b = cr;//b為int,頂層const和引用均被忽略

auto c = &ci;//c為指向常量int的指標,保留底層const

如果要使auto型別為頂層const:

int i = 1;

const auto a = i;//a為const int 型別

如果decltype使用的表示式是乙個變數,decltype會返回該變數的型別(包括引用和頂層const)。

迴圈巨集的優秀替代品——範圍for語句

適用度:★★★★★

什麼?就算有了auto型別指示符,遍歷容器/陣列每乙個元素你還是嫌麻煩?沒事,讓範圍for語句來幫你。

原來這麼遍歷容器/陣列每乙個元素

vectorvec;

for(auto it = vec.begin();it != vec.end();it++)

cout << *it << " ";

現在這麼寫:

vectorvec;

for(auto it : vec)

cout << it << " ";

注意,範圍for語句只能遍歷每乙個元素,所以像遍歷1到10這種操作還是得自己乖乖寫for迴圈:)。

複雜返回值必備——尾置返回型別

適用度:★★★★☆

普通函式完全不必要尾置返回型別,但是當函式返回型別複雜起來時,尾置返回型別就很有用了。

int (*func(int i))[10]

//func(int i)表示呼叫函式時,需要乙個int型別的引數;

//(*func(int i))表示對呼叫func的結果執行解引用的操作;

//(*func(int i))[10]表示解引用之後得到乙個維度為10的陣列;

//int (*func(int i))[10]表示陣列的資料型別為int;

很複雜,對吧?(當然對於dalao來說小菜一碟)當返回型別更加複雜時,常規寫法將會成為debug噩夢。(話說markdown好像識別不了尾置返回型別誒)。

//返回一維陣列

auto func(int i) -> int(*)[10]

還有更複雜的(我太蒻了給不出常規寫法了)

二維陣列:

auto func(int i) -> int(*)[10][10]

二重指標:

auto func(int i) -> int **

除了陣列特殊一些以外,平時定義變數怎麼寫,尾置返回型別就怎麼寫。程式瞬間清爽了許多有木有。

如果返回值更加複雜,連尾置返回型別的作用都顯得微乎其微了怎麼辦?這時候——

配合decltype食用效果更佳

auto func(int a,int b) -> decltype(a+b)

什麼?你連尾置返回型別都嫌麻煩?c++14可以滿足你的需求。沒錯,連尾置返回型別都可以省了,直接返回型別auto就可以了orz。

你不知道的 和

開發中,編寫有一定逼格的 是每個程式猿都追求的。經常用來判斷的符號 和 也經常用來定義變數哦,你知道嗎?邏輯與 在有乙個運算元不是布林值的情況下,就不一定返回布林值。比如以下情況 1 第乙個運算元是物件,返回第二個數 var myinfo console.log myinfo 2 輸出22 第二個運...

你不知道的box shadow

我們可以僅使用乙個div利用shadow配合animation實現很多豐富的效果 github 求 必需。水平陰影的位置。允許負值。v shadow 必需。垂直陰影的位置。允許負值。blur 可選。模糊距離。spread 可選。陰影的尺寸。color 可選。陰影的顏色。請參閱 css 顏色值。ins...

你不知道的 gitignore

乙個.gitignore檔案顯式地指定了哪些檔案不應被git追蹤,即被git忽略掉。在被gitignore之前已經被git追蹤的檔案不受gitignore規則的影響。關於gitignore規則的詳情請繼續往下看。gitignore檔案中的每一行都指定了一種匹配模式。通常來說,git會從多個可能的規則...