Kernel Panic 在這篇文章中總結了 C++11 中的 5 個實用特性:自動型別推導、強型別列舉、Unique 指標、static_assert、Lambdas 表示式。
自動型別推導
auto 關鍵字讓使用者得以使用 C++ 內建的型別推導特性。
1 2 |
std::string something = somethingthatreturnsastring.getString(); auto something = somethingthatreturnsastring.getString(); |
Auto 關鍵字會對上述自變數(something)進行自動推導,得出其應該是 string 型別的結論,並在 auto 出現的地方用正確的型別進行替換。這個特性對迭代器特別有用。
1 2 3 4 |
for(std::vector<T>::iterator it = x.begin(); it != x.end(); i++) { it->something(); } |
上述程式碼可以寫成:
1 2 3 4 |
for(auto it = x.begin(); it != x.end(); i++) { it->something(); } |
贊! 程式碼看上去簡潔多了!
強型別列舉
這個特性可以有效避免列舉型別的命名衝突,從而消除很多潛在的 bug。在舊版本的 C++ 中,程式設計師必須為每一個列舉項設定一個全域性唯一的名字。例如,如果你給一個列舉項取名叫 None,那麼其他的列舉集合就不能再用這個名字了。但是現在,你可以這麼做了!(譯註:作者下面給的例子彷彿和上面的文字不是非常搭配//myEnum ::All 和 myEnum::All是不是存在差異?)
1 2 3 |
enum class myEnum {None, One, All}; myEnum o = myEnum ::All; auto p = myEnum::All; // 同樣有效 |
Lambdas 表示式
Lambda 表示式簡單說就是個匿名函式(譯註:原文為in-place function,意思是“用來鑲嵌的函式”,但是匿名函式能更精確表達這個含義)。對於迭代器以及for 迴圈非常有用,這種函式你只需要在程式的某一處使用一次,所以沒有必要專門在程式裡明確定義它。Lambda 表示式並沒有讓 C++ 在邏輯表達上做到“及以往之不可及”的程度,它是一種受函數語言程式設計思想影響而引入的語言特性,能夠讓程式更緊湊。Lambda 表示式的最簡形式是下面這樣的:
[]() { }
加上所有可能的操作符,會是這樣:
1 |
[]() mutable -> T { } |
其中[]是捕獲列表,()是引數列表,{}是函式體
Capture List 捕獲列表
捕獲列表定義了什麼型別的東西可以從 Lambda 表示式之外匹配到函式體中來。可以包含以下這些:
- 一個值:[x]
- 一個引用 [&x]
- 當前範圍內任意變數的引用 [&]
- 同3,但是通過變數的值
你可以對上面的各項進行任意混合,只要用逗號隔開即可 [x, &y]
Argument List 引數列表
引數列表和 C++ 函式的引數列表是一個概念。
Function Body 函式體
函式體是指在 Lambda 表示式被呼叫時真正執行的程式碼。
Return Type Deduction
返回值推斷
如果 Lambda 表示式只有一個返回宣告,那麼返回值型別就可以省略,其型別就是隱式型別:decltype(return_statement)
可變 Labmda
如果一個 Lambda 表示式被標記為 mutable(例如:[]() mutable{ }),那麼對於按值捕獲的數值來說,在函式體內就允許對這些值進行修改操作。
下面舉個例子:
1 2 3 4 5 6 7 8 9 10 |
int main() { char s[]="Hello World!"; int Uppercase = 0; //lambda會改變這個變數的值 for_each(s, s+sizeof(s), [&Uppercase] (char c) { if (isupper(c)) Uppercase++; }); cout<< Uppercase<<" uppercase letters in: "<< s<<endl; } |
Unique 指標
Unique 指標是 C++11 版本的智慧指標類。
一旦你用 unique_ptr 關鍵字定義了一個物件,那麼下列事件只要發生一個,物件就會被銷燬並釋放記憶體:
- unique_ptr 管理的物件被銷燬。
- unique_ptr 管理的物件通過賦值操作符指向另一個指標,或呼叫了reset()方法。
對於不想了解太多細節的使用者來說,這就意味著如果你使用了 unique 指標的語義,那麼在跳出作用域之前,你就不用手動回收物件的記憶體了。
以前,我們需要這麼寫程式碼:
1 |
YourObject * obj = new YourObject(); |
然後在程式的最後你一定要記得釋放記憶體:
1 |
delete(obj); |
否則你可就造成記憶體洩露了。而現在,
1 |
std::unique_ptr<YourObject> obj(new YourObject()); |
當 obj 跳出作用域範圍之外的時候,記憶體將會被自動回收。
static_assert
static_assert 簡單說就是一個在編譯期執行的斷言。例如,你可以這麼做:
1 |
static_assert(sizeof(unsigned int) * CHAR_BIT == 32); |
假設由於系統的原因造成了上述的邏輯判斷的失敗,那麼 static_assert 就會斷言失敗。
它的另一種用途,是和 C++ 特徵型別搭配使用。比如:
1 |
static_assert(std::is_pod<yourstruct>::value, "Not a pod struct!"); |
POD 是指“簡單資料”(Plain Old Data)結構,也就是說,它是一個的類(你可以用struct關鍵字定義,也可以用class關鍵字定義),但沒有建構函式,解構函式和虛成員函式。所以,如果一個愚蠢的菜鳥程式設計師企圖給這種型別增加建構函式的話,static_assert 就會在編譯的時候阻止這種行為,並報錯。這對程式碼維護來說可是非常有用的。
當然 C++ 還有很多有用的特性,我希望在以後的文章中能給大家介紹更多。謝謝大家的關注!
打賞支援我翻譯更多好文章,謝謝!
打賞譯者
打賞支援我翻譯更多好文章,謝謝!