常用的C++11特性(面試易考)

大二的時候看過《C++Primer》,瞭解過C++11,因此就在簡歷上寫上了解C++11,結果就是頻頻被問到有關C++11。。。發現自己答的並不算太好~

因此,簡單總結一下,我在找實習的過程被問到的C++11特性。


1. nullptr

注意在C++中NULL僅僅是define NULL 0的一個宏定義,因此,有時候會產生歧義

比如f(char*)和f(int),參數傳NULL的話到底該調用哪個?事實上,在VS下測試這樣的函數重載會優先調用f(int),但是f(char *)也是正確的,因此C++引入nullptr來避免這個問題。

更多請參考nullptr, NULL

2. auto, decltype

兩者支持類型推導,獲取

int a = 0;
decltype(a) b = 3;
cout << b << endl;

3.範圍for

常常和auto結合

比如

int arr[] = {1,2,3,4,5};
for(int& e : arr) 
{
  e = e*e;
}

4.智能指針

基於RAII原則,引入shared_ptr, unique _ptr等等,具體可參見智能指針和RAII

5. 新增容器

  1. array最早是在boost中出現:http://www.boost.org/doc/libs/1_61_0/doc/html/array.html
    當時的初衷是希望提供一個在棧上分配的,定長數組,而且可以使用stl中的模板算法。

  2. unordered_map unordered_set
    同樣是來至boost的組件:http://www.boost.org/doc/libs/1_61_0/doc/html/unordered.html
    在早期的標準庫stl中是隻有紅黑樹map,而沒有hash map的。
    所以boost提供了unordered這個組件,並且在c++11中進入了標準庫。
    unordered_ map提供了和map類似的接口,只是map是有序,而unordered_map因爲採用hash map的數據結構,所以是無序的。

    關於unordered_map和map的使用場景:

    1. 查找速度:unordered_map底層是一個hash _ table,一般來說hash函數,hash衝突解決的好,可以達到O(1),map底層是一棵紅黑樹,效率大概是O(logn)
    2. 內存問題,unordered_map是利用了空間換時間,哈希表的元素越少,hash衝突可能性也就越少,效-也就越接近於O(1),但是這樣一來,它的空間利用率也越小;所以一般來說,哈希表的裝填因子大概在0.7-0.8。

6.右值引用,移動構造函數

分清楚什麼是左值和右值,一個比較簡易的方法就是能否取地址,能取地址的則爲左值。

爲什麼引入右值機制?主要是爲了效率,在

右值一般爲臨時變量,字面常量也屬於右值,因爲臨時變量往往在後面不可使用或者說不再使用,因此,我們可以steal竊取他們的資源。

我們看一個例子:

class A
{
public:
    A()
    {
        cout << "A()" << endl;
    }
    A(const A&)
    {
        cout << "A(const A&)" << endl;
    }


};

vector<A> Get()
{
    vector<A> tmp;
    tmp.push_back(A());
    cout << "Get end" << endl << endl;
    return tmp;
}

int main()
{
    vector<A> v;
    v = Get();

    return 0;
}

在C99標準下編譯後結果如下:

這裏寫圖片描述

在C++11標準下編譯後結果如下:

這裏寫代碼片

爲什麼會這樣?

這是因爲:

對於Get函數,它會返回一個臨時vector < A> 對象,當main函數中,執行到v = Get()時候,它會將v
中現有成員都刪除,然後將這個臨時對象裏面所有內容都拷貝到v中,最後析構這個臨時對象。

我們知道拷貝複製的代價還是很大,對於這種情況,我們完全可以直接將v中資源和這個臨時對象中的資源交換,然後再刪除臨時對象,這樣就避免複製操作,提高了效率。

右值引用必須綁定在右值上,但是我們可以通過std::move函數“綁定左值”

右值引用因爲綁定對象即將被銷燬,意味着沒有人會繼續訪問他們,所以就可以把他們(的資源)steal過來。

雖然不能將右值引用綁在左值上,但通過利用utility頭文件新增的函數模板move,它返回傳入對象的右值引用,可以達到 steal的效果。

int &&rr3 = std::move(rr2); // ok
再提醒:一旦使用了move,編譯器就默認傳入對象已經不打算使用了,是可以被銷燬的,move之後該對象的值已經不確定,不要再訪問。還有由於對象偷取與複製的差別巨大,不注意會產生非常難定位的bug,所以所有使用move的地方一定要使用全稱std::move,給大家以提醒。(其實c++11在algorithm頭文件也新增了一個move,參數與意義都與此截然不同)。

移動構造函數等

  1. move構造函數

對象可以被複制構造,滿足條件場景下,自然也就可以被“剪切”構造。move構造函數就用於此,它也屬於copy-control系列函數,後者的5個成員現在更新爲:拷貝構造函數,複製性質的賦值運算符,move構造函數,move性質的賦值運算符,析構函數。

class base
{
public:
int* p;
base():{p = new(…);}
~base(){delete p;}
base(base&& ref):p(ref.p){ref.p = nullptr;}

};
新創建對象的指針p接管了來源對象指針p所持有的資源,並將後者置空。特別注意move構造函數一定要來源對象內部存儲資源的變量設置正確的狀態,如指針置空等,避免來源對象析構時內存誤釋放。

move語義不僅僅用於右值,也用於左值。標準庫提供了std::move方法,將左值轉換成右值。因此,對於swap函數,我們可以這樣實現:

template<class T>
void swap(T& a, T& b)
{
    T temp(std::move(a));
    a = std::move(b);
    b = std::move(temp);
}

參考:
http://www.cnblogs.com/TianFang/archive/2013/01/26/2878356.html

http://www.cnblogs.com/virusolf/p/5604394.html

C++11 中值得關注的幾大變化(詳解)

發佈了96 篇原創文章 · 獲贊 119 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章