C++ 是一種強大的編程語言,但也由於其複雜性一直讓用戶望而卻步。後來,C++ 決定作出改變,而後發展至今,成了編程社區最受歡迎的語言之一。C++ 有一些新特性很是好用,本文對此進行了介紹,好比 auto、lambda、constexpr、tuple、智能指針等。c++
做爲一門編程語言,C++已經進化了不少。編程
固然,這些改變不是一晚上之間發生的。曾幾什麼時候,C++缺少活力,致使人們不太喜歡這門語言。安全
可是,當 C++標準委員會決定加快轉變時,狀況就不一樣了。數據結構
自 2011 年以來,C++已經成爲一種不斷髮展的動態語言,而這正是不少人所期許的。編程語言
不要誤覺得是這門語言變得簡單了,實際並無。它仍然是被普遍使用的最難編程語言之一。可是相比於以前的版本,確實對用戶更加友好了。函數
今天,咱們深刻發掘一下每位開發者都應該瞭解的新特性(這些新特性從 C++11 時開始出現,距今已有八年曆史了)。注意,本文略過了一些高級特性,可能會在之後的內容中詳細探討。this
auto 概念spa
當 C++11 第一次引入 auto,一切都變得更簡單了。3d
auto 的概念是讓 c++編譯器在編譯時自動推斷數據的類型,而不是每次都要求你手動聲明類型。若是你的數據類型是 map<string,vector<pair<int,int>>> <string,vector<pair這樣的,事情會變得很是方便。</string,vector<pair指針
看一下第五行。沒有 initializer 時你不能聲明某些東西,這不難理解。像第五行這樣,編譯器是沒法推斷數據類型的。
最初,auto 的使用是很是受限的。在以後的版本中,auto 變得更增強大!
第 7 和第 8 行中,我使用了花括號初始化。這個特性也是 C++11 中新加入的。
記住,當使用 auto 時,必須確保你的編譯器能夠經過某種方式推斷數據類型。
如今問題來了,若是我寫 auto a = {1, 2, 3} 會發生什麼?會有編譯錯誤嗎?這是向量嗎?
實際上,C++11 引入了 std::initializer_list<type>,若是聲明爲 auto,那麼初始化列表會被認爲是這種輕量級容器。
最後,就像前面提到的,當你使用複雜的數據類型時,編譯器推斷數據類型會很是有用。
不要忘記查看第 25 行!表達式 auto [v1,v2] = itr.second 是 C++17 的新特性。這被稱爲結構化綁定。在以前的版本中,每一個變量必需要分別進行提取,然而結構化綁定會使這個過程方便不少。
另外,若是你想經過引用獲取數據,只須要添加一個像 auto &[v1,v2] = itr.second 這樣的符號,很是簡潔。
lambda 表達式
C++11 引入了 lambda 表達式,該表達式和 JavaScript 中的匿名函數很是類似。它們是沒有命名的函數對象,而且基於一些簡潔的語法在不一樣的做用域捕獲變量,它們還能夠分配給變量。
當你想在代碼中快速實現一些小功能但並不想爲此單獨編寫整個函數時,lambda 很是有用。另外一種很是廣泛的應用是將其做爲比較函數。
上面的例子中有不少細節。
首先,要注意到列表初始化爲你節省了多少代碼。而後是通用的 begin() 和 end(),它們一樣也是 C++11 中新添加的。而後是做爲數據比較器的 lambda 函數。lambda 函數的參數被聲明爲 auto,這是 c++14 中新增的。在此以前,是不能夠用 auto 做爲函數參數的。
這裏使用方括號[]做爲 lambda 表達式的開始。它定義了 lambda 函數的做用域,即它對局部變量和對象有多少權限。
下面是一些現代 c++中的相關定義:
[]表明空。所以你不能夠在 lambda 表達式中使用任何外部做用域的局部變量。只可使用參數。
[=]表明可經過值獲取做用域內的局部對象(局部變量和參數),即你只可使用但不可修改。
[&]表明可經過引用獲取做用域內的局部對象(局部變量和參數),即你能夠像下面例子中同樣修改它。
[this]表明可經過值獲取 this 指針。
[a,&b]表明經過值獲取對象 a, 經過引用獲取對象 b。
所以,若是你想在 lambda 函數中將數據轉換成其餘形式,你能夠像下面這段代碼同樣,利用做用域來使用 lambda。
在上面的例子中,若是你在 lambda 表達式中使用 [factor] 取值的方式獲取了局部變量,你就不能在第五行中修改 factor,由於你沒有權利這樣作。不要濫用你的權限!
最後,注意這裏 var 是引用。這保證了在 lambda 函數內的任何改變都會真正改變 vector。
if 或 switch 語句裏的初始狀態
當我瞭解了 c++17 的這個特性以後我很是喜歡。
顯然,如今你能夠在 if/switch 語句塊內初始化變量而且進行條件檢查了。這對保持代碼的緊湊和簡潔是很是有幫助的。一般形式以下:
編譯時執行 constexpr
constexpr 很是酷!
假設你有一些表達式要計算,而且它的值一旦初始化就不會改變。你能夠預先計算該值而且做爲宏來使用。或者像 C++11 中提供的,你可使用 constexpr。
編程人員傾向於儘量減小程序的運行時間。所以若是某些操做可讓編譯器來作,就能夠減輕運行時的負擔,從而提升時間效率。
上面的代碼是 constexpr 的一個常見例子。
因爲咱們聲明 fibonacci 計算函數爲 constexpr,編譯器會在編譯時預先計算 fib(20) 的值。因此編譯結束後,它能夠把 const long long bigval = fib(20) 替換爲 const long long bigval = 2432902008176640000;
須要注意的是,傳遞的參數是 const 值。這是聲明爲 constexpr 的函數很是重要的一點,傳遞的參數一樣要是 constexpr 或者 const。不然,該函數會像普通函數同樣執行,即不會在編譯時預先計算。
變量也一樣能夠是 constexpr。這種狀況下,你應該能夠猜到,這些變量一樣也是編譯時計算的。不然,會出現編譯錯誤。
有趣的是,在以後的 c++17 中,又引入了 constexpr-if 和 constexpr-lambda。
tuple
和 pair 很是類似,tuple 是一組各類數據類型的固定大小值的集合。
有時候,使用 std::array會比使用 tuple 更加方便。array 和普通 C 類型的 array 很是類似,但具備 C++標準庫的一些特性。這種數據結構是 C++11 中新增的。
類模版參數推斷
名字有點長。從 c++17 開始,參數推斷也適用於標準類模版。此前,該特性只支持函數模版。
所以,
類型推斷是隱式完成的。這對 tuple 來講變得更加方便。
若是你不熟悉 C++模版,那麼上述特性可能對你來講不是很好理解。
智能指針
指針也可能並很差用。
因爲 C++給編程人員提供了很大的自由度,有時這種自由可能反而會成爲絆腳石。在多數狀況下,都是指針在起反面做用。
幸運的是,C++11 引入了智能指針,它比以前的原始指針更加方便,能夠經過適當地指針釋放幫助開發者避免內存泄漏,同時也提供了額外的安全機制。
一開始我想在這篇文章中詳細探討一下智能指針,但顯然重要的細節很是多,值得單開一篇來寫,所以近期應該會出一篇相關文章。