1. 程式人生 > 其它 >Sketch中文版教程,已加星標的更新如何使用?什麼是Sketch星標功能?

Sketch中文版教程,已加星標的更新如何使用?什麼是Sketch星標功能?

前面一段時間啃完了《C++ Primer》第5版,對於書中的C++11新特性,摘抄在這裡做個筆記。  

一、C++基礎

1、列表初始化

作為C++11新標準的一部分,用花括號來初始化變數得到了全面應用,而在此之前,這種初始化的形式僅在某些受限的場合下才能使用。

現在,無論是初始化物件還是某些時候為物件賦新值,都可以使用這樣一組由花括號括起來的初始值了。

當用於內建型別的變數時,這種初始化形式有一個重要特點:如果我們使用列表初始化且初始值存在丟失資訊的風險,則編譯器將報錯:

 

C++11新標準還提供了另外一種為vector物件的元素賦初值的方法,即列表初始化。此時,用花括號括起來的0個或多個初始元素值被賦給vector物件:

 

關聯容器的列表初始化:

 

pair的列表初始化:

 

自定義類的列表初始化:

 

2、空指標

空指標不指向任何物件,幾個生成空指標的方法:

得到空指標最直接的辦法就是用字面值nullptr來初始化指標,這也是C++11新標準剛剛引入的一種方法。nullptr是一種特殊型別的字面值,它可以被轉換成任意其他的指標型別。

過去的程式還會用到一個名為NULL的預處理變數(preprocessor variable)來給指標賦值,這個變數在標頭檔案cstdlib中定義,它的值就是0。

 

3、constexpr和常量表達式

常量表達式是指值不會改變並且在編譯過程就能得到計算結果的表示式。顯然,字面值屬於常量表達式,用常量表達式初始化的const物件也是常量表達式。

一個物件(或表示式)是不是常量表達式由它的資料型別和初始值共同決定,例如:

儘管staff_size的初始值是個字面值常量,但由於它的資料型別只是一個普通int而非const int,所以它不屬於常量表達式。另一方面,儘管sz本身是一個常量,但它的具體值直到執行時才能獲取到,所以也不是常量表達式。

在複雜系統中,很難分辨一個初始值到底是不是常量表達式。所以導致在實際使用中,物件的定義和使用根本就是兩回事。

C++11新標準規定,允許將變數宣告為constexpr型別以便由編譯器來驗證變數的值是否是一個常量表達式。宣告為constexpr的變數一定是一個常量,而且必須用常量表達式初始化:

指標和constexpr:

p和q的型別相差甚遠,p是一個指向常量的指標,而q是一個常量指標,其中的關鍵在於constexpr把它所定義的物件置為了頂層const。

與其他常量指標類似,constexpr指標既可以指向常量也可以指向一個非常量:

對頂層常量、底層常量、常量和指標、引用結合一直還比較模糊。

 

4、constexpr函式

constexpr函式是指能用於常量表達式(參見2.4.4節,第58頁)的函式。定義constexpr函式的方法與其他函式類似,不過要遵循幾項約定:函式的返回型別及所有形參的型別都得是字面值型別(參見2.4.4節,第59頁),而且函式體中必須有且只有一條return語句:

constexpr函式體內也可以包含其他語句,只要這些語句在執行時不執行任何操作就行。例如,constexpr函式中可以有空語句、類型別名(參見2.5.1節,第60頁)以及using宣告。

 

5、類型別名

傳統的方法是使用關鍵字typedef:

新標準規定了一種新的方法,使用別名宣告(alias declaration)來定義型別的別名:

 

6、auto型別說明符

有時在宣告變數的時候,可能並不清楚的知道表示式的型別。

C++11新標準引入了auto型別說明符,用它就能讓編譯器替我們去分析表示式所屬的型別。和原來那些只對應一種特定型別的說明符(比如double)不同,auto讓編譯器通過初始值來推算變數的型別。顯然,auto定義的變數必須有初始值:

使用auto也能在一條語句中宣告多個變數。因為一條宣告語句只能有一個基本資料型別,所以該語句中所有變數的初始基本資料型別都必須一樣:

編譯器推斷出來的auto型別有時候和初始值的型別並不完全一樣,編譯器會適當地改變結果型別使其更符合初始化規則。

首先,正如我們所熟知的,使用引用其實是使用引用的物件,特別是當引用被用作初始值時,真正參與初始化的其實是引用物件的值。此時編譯器以引用物件的型別作為auto的型別:

其次,auto一般會忽略掉頂層const(參見2.4.3節,第57頁),同時底層const則會保留下來,比如當初始值是一個指向常量的指標時:

string的size_type:

在C++11中就可以使用auto或者decltype,而不用關注size_type的細節。

 

如果我們提供了一個括號包圍的初始化器,就可以使用auto從此初始化器來推斷我們想要分配的物件的型別。但是,由於編譯器要用初始化器的型別來推斷要分配的型別,只有當括號中僅有單一初始化器時才可以使用auto:

 

7、decltype型別指示符

有時會遇到這種情況:希望從表示式的型別推斷出要定義的變數的型別,但是不想用該表示式的值初始化變數。為了滿足這一要求,C++11新標準引入了第二種型別說明符decltype,它的作用是選擇並返回運算元的資料型別

decltype處理頂層const和引用的方式與auto有些許不同。如果decltype使用的表示式是一個變數,則decltype返回該變數的型別(包括頂層const和引用在內):

特別:decltype((variable))(注意是雙層括號)的結果永遠是引用,而decltype(variable)結果只有當variable本身就是一個引用時才是引用。

 

8、範圍for

如果想對string物件中的每個字元做點兒什麼操作,目前最好的辦法是使用C++11新標準提供的一種語句:範圍for(range for)語句。這種語句遍歷給定序列中的每個元素並對序列中的每個值執行某種操作,其語法形式是:

其中,expression部分是一個物件,用於表示一個序列。declaration部分負責定義一個變數,該變數將被用於訪問序列中的基礎元素。每次迭代,declaration部分的變數會被初始化為expression部分的下一個元素值。

 

C++11中處理多維陣列:

在這裡給一個二維陣列賦初值:

與前面對比:

 

9、迭代器

const_iterator和常量指標差不多,能讀取但不能修改它所指的元素值。相反,iterator的物件可讀可寫。

begin和end返回的具體型別由物件是否是常量決定,如果物件是常量,begin和end返回const_iterator;如果物件不是常量,返回iterator:

有時候這種預設的行為並非我們所要。如果物件只需讀操作而無須寫操作的話最好使用常量型別(比如const_iterator)。為了便於專門得到const_iterator型別的返回值,C++11新標準引入了兩個新函式,分別是cbegin和cend:

 

陣列操作:

儘管能計算得到尾後指標,但這種用法極易出錯。為了讓指標的使用更簡單、更安全,C++11新標準引入了兩個名為begin和end的函式。這兩個函式與容器中的兩個同名成員功能類似,不過陣列畢竟不是類型別,因此這兩個函式不是成員函式。正確的使用形式是將陣列作為它們的引數:

案例:

特別要注意,尾後指標不能執行解引用和遞增操作。

 

10、算術運算

除法:C++語言的早期版本允許結果為負值的商向上或向下取整,C++11新標準則規定商一律向0取整(即直接切除小數部分)。

 

11、initializer_list形參

如果函式的實引數量未知但是全部實參的型別都相同,我們可以使用initializer_list型別的形參。initializer_list是一種標準庫型別,用於表示某種特定型別的值的陣列。initializer_list型別定義在同名的標頭檔案中,它提供的操作:

和vector一樣,initializer_list也是一種模板型別。定義initializer_list物件時,必須說明列表中所含元素的型別:

示例:

作用於initializer_list物件的begin和end操作類似於vector對應的成員。begin()成員提供一個指向列表首元素的指標,end()成員提供一個指向列表尾後元素的指標。

 

12、列表初始化返回值

C++11新標準規定,函式可以返回花括號包圍的值的列表。類似於其他返回結果,此處的列表也用來對錶示函式返回的臨時量進行初始化。

如果函式返回的是內建型別,則花括號包圍的列表最多包含一個值,而且該值所佔空間不應該大於目標型別的空間。如果函式返回的是類型別,由類本身定義初始值如何使用。

 

13、尾置返回型別

返回陣列指標:因為陣列不能被拷貝,所以函式不能返回陣列。不過,函式可以返回陣列的指標或引用。

宣告一個返回陣列指標的函式:

在C++11新標準中還有一種可以簡化上述func宣告的方法,就是使用尾置返回型別(trailing return type)。任何函式的定義都能使用尾置返回,但是這種形式對於返回型別比較複雜的函式最有效,比如返回型別是陣列的指標或者陣列的引用。尾置返回型別跟在形參列表後面並以一個->符號開頭。為了表示函式真正的返回型別跟在形參列表之後,我們在本應該出現返回型別的地方放置一個auto:

使用decltype:如果我們知道函式返回的指標將指向哪個陣列,就可以使用decltype關鍵字宣告返回型別。

注意:decltype並不負責把陣列型別轉換成對應的指標,所以decltype的結果是個陣列,要想表示arrPtr返回指標還必須在函式宣告時加一個*符號。

 

 

 

 

二、C++標準庫

1、檔案流建立

在C++11中,ifile可以是string的引數,也可以是C風格字元陣列。

舊版本的標準庫只允許C風格字元陣列。

 

2、順序容器

forward_list和array是新C++標準增加的型別。與內建陣列相比,array是一種更安全、更容易使用的陣列型別。與內建陣列類似,array物件的大小是固定的。因此,array不支援新增和刪除元素以及改變容器大小的操作。forward_list的設計目標是達到與最好的手寫的單向連結串列資料結構相當的效能。因此,forward_list沒有size操作,因為儲存或計算其大小就會比手寫連結串列多出額外的開銷。對其他容器而言,size保證是一個快速的常量時間的操作。

 

array的使用:

array多維:

 

順序容器的操作:

在C++11中,接受元素個數或範圍的insert版本返回指向第一個新加入元素的迭代器。(在舊版本的標準庫中,這些操作返回void。)如果範圍為空,不插入任何元素,insert操作會將第一個引數返回。

新標準引入了三個新成員——emplace_front、emplace和emplace_back,這些操作構造而不是拷貝元素。這些操作分別對應push_front、insert和push_back,允許我們將元素放置在容器頭部、一個指定位置之前或容器尾部。

 

在新標準庫中,我們可以呼叫shrink_to_fit來要求deque、vector或string退回不需要的記憶體空間。此函式指出我們不再需要任何多餘的記憶體空間。但是,具體的實現可以選擇忽略此請求。也就是說,呼叫shrink_to_fit也並不保證一定退回記憶體空間。

 

3、lambda表示式

一個lambda表示式表示一個可呼叫的程式碼單元。我們可以將其理解為一個未命名的行內函數。與任何函式類似,一個lambda具有一個返回型別、一個引數列表和一個函式體。但與函式不同,lambda可能定義在函式內部。一個lambda表示式具有如下形式

其中,capture list(捕獲列表)是一個lambda所在函式中定義的區域性變數的列表(通常為空);return type、parameter list和function body與任何普通函式一樣,分別表示返回型別、引數列表和函式體。但是,與普通函式不同,lambda必須使用尾置返回來指定返回型別。

可以忽略引數列表和返回型別,但必須永遠包含捕獲列表和函式體:

lambda的呼叫方式與普通函式的呼叫方式相同,都是使用呼叫運算子:

與普通函式不同,lambda不能有預設引數。因此,一個lambda呼叫的實引數目永遠與形引數目相等。

捕獲列表其實是申明要用到的所在函式的區域性變數。空捕獲列表表明此lambda不使用它所在函式中的任何區域性變數。

舉例:lambda所在函式有一個 sz 變數,如果該lambda表示式要使用這個 sz 變數,那麼需要寫在捕獲列表中,如果不捕獲,那麼就不能使用。

捕獲分為 值捕獲 和 引用捕獲。引用捕獲:

 

隱式捕獲:

除了顯式列出我們希望使用的來自所在函式的變數之外,還可以讓編譯器根據lambda體中的程式碼來推斷我們要使用哪些變數。為了指示編譯器推斷捕獲列表,應在捕獲列表中寫一個&或=。&告訴編譯器採用捕獲引用方式,=則表示採用值捕獲方式。

如果我們希望對一部分變數採用值捕獲,對其他變數採用引用捕獲,可以混合使用隱式捕獲和顯式捕獲:

當我們混合使用隱式捕獲和顯式捕獲時,捕獲列表中的第一個元素必須是一個&或=。此符號指定了預設捕獲方式為引用或值。

當混合使用隱式捕獲和顯式捕獲時,顯式捕獲的變數必須使用與隱式捕獲不同的方式。即,如果隱式捕獲是引用方式(使用了&),則顯式捕獲命名變數必須採用值方式,因此不能在其名字前使用&。類似的,如果隱式捕獲採用的是值方式(使用了=),則顯式捕獲命名變數必須採用引用方式,即,在名字前使用&。

預設情況下,對於一個值被拷貝的變數,lambda不會改變其值。如果我們希望能改變一個被捕獲的變數的值,就必須在引數列表首加上關鍵字mutable。

 

4、智慧指標

智慧指標的行為類似常規指標,重要的區別是它負責自動釋放所指向的物件。

shared_ptr允許多個指標指向同一個物件;

unique_ptr則“獨佔”所指向的物件。

標準庫還定義了一個名為weak_ptr的伴隨類,它是一種弱引用,指向shared_ptr所管理的物件。

類似vector,智慧指標也是模板。因此,當我們建立一個智慧指標時,必須提供額外的資訊——指標可以指向的型別。

預設初始化的智慧指標中儲存著一個空指標。

智慧指標的使用方式與普通指標類似。解引用一個智慧指標返回它指向的物件。如果在一個條件判斷中使用智慧指標,效果就是檢測它是否為空:

make_shared函式

最安全的分配和使用動態記憶體的方法是呼叫一個名為make_shared的標準庫函式。此函式在動態記憶體中分配一個物件並初始化它,返回指向此物件的shared_ptr。

當進行拷貝或賦值操作時,每個shared_ptr都會記錄有多少個其他shared_ptr指向相同的物件:

一旦一個shared_ptr的計數器變為0,它就會自動釋放自己所管理的物件。

每個shared_ptr都有一個關聯的計數器,通常稱其為引用計數(reference count)。無論何時我們拷貝一個shared_ptr,計數器都會遞增。例如,當用一個shared_ptr初始化另一個shared_ptr,或將它作為引數傳遞給一個函式以及作為函式的返回值時,它所關聯的計數器就會遞增。

 

不要將內建指標和智慧指標混合使用:

 

智慧指標與異常:

如果使用智慧指標,即使程式塊過早結束,智慧指標類也能確保在記憶體不再需要時將其釋放,:

原因是無論是正常處理結束還是異常退出,區域性變數sp都會被銷燬,在sp被銷燬的時候會檢查引用計數。

而如果使用的是內建指標,則這裡不會被自動釋放。

 

如果智慧指標指向的動態記憶體沒有解構函式,可以給它傳遞一個刪除器來確保shared_ptr中儲存的指標進行釋放操作。

 

智慧指標陷阱:

不使用相同的內建指標值初始化(或reset)多個智慧指標。

不delete get()返回的指標。

不使用get()初始化或reset另一個智慧指標。

如果你使用get()返回的指標,記住當最後一個對應的智慧指標銷燬後,你的指標就變為無效了。

如果你使用智慧指標管理的資源不是new分配的記憶體,記住傳遞給它一個刪除器。

 

unique_ptr:

一個unique_ptr“擁有”它所指向的物件。與shared_ptr不同,某個時刻只能有一個unique_ptr指向一個給定物件。當unique_ptr被銷燬時,它所指向的物件也被銷燬。

 

weak_ptr:

是一種不控制所指向物件生存期的智慧指標,它指向由一個shared_ptr管理的物件。將一個weak_ptr繫結到一個shared_ptr不會改變shared_ptr的引用計數。

由於物件可能不存在,我們不能使用weak_ptr直接訪問物件,而必須呼叫lock。此函式檢查weak_ptr指向的物件是否仍存在。如果存在,lock返回一個指向共享物件的shared_ptr。與任何其他shared_ptr類似,只要此shared_ptr存在,它所指向的底層物件也就會一直存在。例如:

 

 

三、類設計

1、建構函式=default、=delete

類 Sales_data 的定義中:

該建構函式不接受任何實參,所以它是一個預設建構函式。

定義這個建構函式的目的僅僅是因為我們既需要其他形式的建構函式,也需要預設的建構函式。我們希望這個函式的作用完全等同於之前使用的合成預設建構函式。

在C++11新標準中,如果我們需要預設的行為,那麼可以通過在引數列表後面寫上= default來要求編譯器生成建構函式。其中,= default既可以和宣告一起出現在類的內部,也可以作為定義出現在類的外部。和其他函式一樣,如果= default在類的內部,則預設建構函式是內聯的;如果它在類的外部,則該成員預設情況下不是內聯的。

 

因為編譯器會生成合成版本,如果為了控制禁止拷貝等操作。

在新標準下,我們可以通過將拷貝建構函式和拷貝賦值運算子定義為刪除的函式(deleted function)來阻止拷貝。刪除的函式是這樣一種函式:我們雖然聲明瞭它們,但不能以任何方式使用它們。在函式的引數列表後面加上=delete來指出我們希望將它定義為刪除的:

 

注意:解構函式不能是刪除函式

值得注意的是,我們不能刪除解構函式。如果解構函式被刪除,就無法銷燬此型別的物件了。對於一個刪除了解構函式的型別,編譯器將不允許定義該型別的變數或建立該類的臨時物件。而且,如果一個類有某個成員的型別刪除了解構函式,我們也不能定義該類的變數或臨時物件。因為如果一個成員的解構函式是刪除的,則該成員無法被銷燬。而如果一個成員無法被銷燬,則物件整體也就無法被銷燬了。

對於刪除了解構函式的型別,雖然我們不能定義這種型別的變數或成員,但可以動態分配這種型別的物件。但是,不能釋放這些物件:

 

在新標準釋出之前,類是通過將其拷貝建構函式和拷貝賦值運算子宣告為private的來阻止拷貝:

希望阻止拷貝的類應該使用=delete來定義它們自己的拷貝建構函式和拷貝賦值運算子,而不應該將它們宣告為private的。

 

2、委託建構函式

C++11新標準擴充套件了建構函式初始值的功能,使得我們可以定義所謂的委託建構函式(delegating constructor)。一個委託建構函式使用它所屬類的其他建構函式執行它自己的初始化過程,或者說它把它自己的一些(或者全部)職責委託給了其他建構函式。

當一個建構函式委託給另一個建構函式時,受委託的建構函式的初始值列表和函式體被依次執行,然後控制權才會交還給委託者的函式體。

 

3、移動建構函式 和 std::move

通過使用新標準庫引入的兩種機制,我們就可以避免string的拷貝。

首先,有一些標準庫類,包括string,都定義了所謂的“移動建構函式”。

第二個機制是一個名為move的標準庫函式,它定義在utility標頭檔案中。目前,關於move我們需要了解兩個關鍵點。首先,當reallocate在新記憶體中構造string時,它必須呼叫move來表示希望使用string的移動建構函式。

 

關於string的移動建構函式如何工作的細節,以及有關實現的任何其他細節,目前都尚未公開。但是,我們知道,移動建構函式通常是將資源從給定物件“移動”而不是拷貝到正在建立的物件。而且我們知道標準庫保證“移後源”(moved-from)string仍然保持一個有效的、可析構的狀態。對於string,我們可以想象每個string都有一個指向char陣列的指標。可以假定string的移動建構函式進行了指標的拷貝,而不是為字元分配記憶體空間然後拷貝字元。

 

標準庫容器、string和shared_ptr類既支援移動也支援拷貝。IO類和unique_ptr類可以移動但不能拷貝。

 

4、右值

為了支援移動操作,新標準引入了一種新的引用型別——右值引用(rvaluereference)。所謂右值引用就是必須繫結到右值的引用。我們通過&&而不是&來獲得右值引用。

右值引用有一個重要的性質——只能繫結到一個將要銷燬的物件。因此,我們可以自由地將一個右值引用的資源“移動”到另一個物件中。

 

左值持久;右值短暫

考察左值和右值表示式的列表,兩者相互區別之處就很明顯了:左值有持久的狀態,而右值要麼是字面常量,要麼是在表示式求值過程中建立的臨時物件。

變數是左值

 

雖然不能將一個右值引用直接繫結到一個左值上,但我們可以顯式地將一個左值轉換為對應的右值引用型別。我們還可以通過呼叫一個名為move的新標準庫函式來獲得繫結到左值上的右值引用,此函式定義在標頭檔案utility中。move函式使用了我們將在16.2.6節中描述的機制來返回給定物件的右值引用。

move呼叫告訴編譯器:我們有一個左值,但我們希望像一個右值一樣處理它。我們必須認識到,

呼叫move就意味著承諾:除了對rr1賦值或銷燬它外,我們將不再使用它。在呼叫move之後,我們不能對移後源物件的值做任何假設。

 

類似string類(及,如果我們自己的類也同時支援移動和拷貝,那麼也能從中受益。為了讓我們自己的型別支援移動操作,需要為其定義移動建構函式和移動賦值運算子。這兩個成員類似對應的拷貝操作,但它們從給定物件“竊取”資源而不是拷貝資源

 

類似拷貝建構函式,移動建構函式的第一個引數是該類型別的一個引用。不同於拷貝建構函式的是,這個引用引數在移動建構函式中是一個右值引用。與拷貝建構函式一樣,任何額外的引數都必須有預設實參。

 

由於一個移後源物件具有不確定的狀態,對其呼叫std::move是危險的。當我們呼叫move時,必須絕對確認移後源物件沒有其他使用者。

5、noexcept

noexcept是我們承諾一個函式不丟擲異常的一種方法。我們在一個函式的引數列表後指定noexcept。

 

對於一個函式來說,noexcept說明要麼出現在該函式的所有宣告語句和定義語句中,要麼一次也不出現。

 

可能出現這樣一種情況:儘管函式聲明瞭它不會丟擲異常,但實際上還是丟擲了。一旦一個noexcept函式丟擲了異常,程式就會呼叫terminate以確保遵守不在執行時丟擲異常的承諾。上述過程對是否執行棧展開未作約定,因此noexcept可以用在兩種情況下:一是我們確認函式不會丟擲異常,二是我們根本不知道該如何處理異常。

 

6、標準庫function型別

C++中的可呼叫物件:函式、函式指標、lambda表示式、bind建立的物件、過載了函式呼叫運算子的類;

上面這些不同型別可能具有相同的呼叫形式:

上面的型別不同,但是呼叫形式都如下:

在C++11中,我們可以使用一個名為function的新的標準庫型別來統一上面。

 

7、顯示型別轉換

型別轉換運算子是類的一種特殊成員函式,負責將一個類型別的值轉換成其他型別:

在實踐中,類很少提供型別轉換運算子;在大多數情況下,如果型別轉換自動發生,可能會有比較意外的結果。

舉個例子:

早期版本中,如果類想定義一個向bool的型別轉換,則它常常遇到一個問題:因為bool是一種算術型別,所以類型別的物件轉換成bool後就能被用在任何需要算術型別的上下文中。這樣的型別轉換可能引發意想不到的結果,特別是當istream含有向bool的型別轉換時,下面的程式碼仍將編譯通過:

因為istream本身並沒有定義<<,所以本來程式碼應該產生錯誤。然而,該程式碼能使用istream的bool型別轉換運算子將cin轉換成bool,而這個bool值接著會被提升成int並用作內建的左移運算子的左側運算物件。這樣一來,提升後的bool值(1或0)最終會被左移42個位置。這一結果顯然與我們的預期大相徑庭。

 

C++11新標準引入了顯式的型別轉換運算子:

 

8、派生類繼承

C++11新標準允許派生類顯式地註明它使用某個成員函式覆蓋了它繼承的虛擬函式。具體做法是在形參列表後面、或者在const成員函式的const關鍵字後面、或者在引用成員函式的引用限定符後面新增一個關鍵字override。

這麼做的好處是在使得程式設計師的意圖更加清晰的同時讓編譯器可以為我們發現一些錯誤。

 

C++11新標準提供了一種防止繼承發生的方法,即在類名後跟一個關鍵字final:

 

“繼承”的建構函式:

在C++11新標準中,派生類能夠重用其直接基類定義的建構函式。

一個類只初始化它的直接基類,出於同樣的原因,一個類也只繼承其直接基類的建構函式。類不能繼承預設、拷貝和移動建構函式。如果派生類沒有直接定義這些建構函式,則編譯器將為派生類合成它們。

 

在C++11新標準中,允許派生類從它的一個或幾個基類中繼承建構函式。但是如果從多個基類中繼承了相同的建構函式(即形參列表完全相同),則程式將產生錯誤:

如果一個類從它的多個基類中繼承了相同的建構函式,則這個類必須為該建構函式定義它自己的版本:

 

 

四、高階主題

1、tuple

tuple是類似pair的模板。每個pair的成員型別都不相同,但每個pair都恰好有兩個成員。不同tuple型別的成員型別也不相同,但一個tuple可以有任意數量的成員。每個確定的tuple型別的成員數目是固定的,但一個tuple型別的成員數目可以與另一個tuple型別不同。

當我們希望將一些資料組合成單一物件,但又不想麻煩地定義一個新資料結構來表示這些資料時,tuple是非常有用的。

 

2、正則表示式

C++正則表示式庫(RE庫),它是新標準庫的一部分。

 

3、隨機數

在以前版本中,依賴於一個簡單的C庫函式rand來生成隨機數。

rand函式有一些問題:即使不是大多數,也有很多程式需要不同範圍的隨機數。一些應用需要隨機浮點數。一些程式需要非均勻分佈的數。而程式設計師為了解決這些問題而試圖轉換rand生成的隨機數的範圍、型別或分佈時,常常會引入非隨機性。

C++11中引入了隨機數引擎類(random-number engines)和隨機數分佈類(random-numberdistribution)。

分佈:

 

4、內聯名稱空間

內聯名稱空間(inlinenamespace)。和普通的巢狀名稱空間不同,內聯名稱空間中的名字可以被外層名稱空間直接使用。也就是說,我們無須在內聯名稱空間的名字前新增表示該名稱空間的字首,通過外層名稱空間的名字就可以直接訪問它。

 

5、列舉

C++11新標準引入了限定作用域的列舉型別(scoped enumeration)。

包含兩種列舉:限定作用域的和不限定作用域的。

 

定義限定作用域的列舉型別的一般形式是:首先是關鍵字enum class(或者等價地使用enum struct),隨後是列舉型別名字以及用花括號括起來的以逗號分隔的列舉成員(enumerator)列表,最後是一個分號:

不限定作用域的列舉:

 

限定作用域列舉型別是為了彌補不限定作用域列舉型別的不足而出現的,不限定作用域的列舉型別不是型別安全的,主要表現在如下幾個方面:

不限定作用域的列舉型別中的列舉成員被視為整數,兩種不同的列舉型別之間可以進行比較。兩種不同型別的資料進行比較,可能帶來資料型別轉換,引起資料表示不完整。

不限定作用域列舉所使用的整數型別及其大小都由實現方法定義,皆無法明確指定。

不限定作用域列舉型別的列舉成員與列舉型別外部資料處在同一個作用域範圍內,多個列舉型別不能有同名的列舉成員。

 

在C++11新標準中,我們可以在enum的名字後加上冒號以及我們想在該enum中使用的型別:

在C++11新標準中,我們可以提前宣告enum。enum的前置宣告(無論隱式地還是顯示地)必須指定其成員的大小:

因為不限定作用域的enum未指定成員的預設大小,因此每個宣告必須指定成員的大小。對於限定作用域的enum來說,我們可以不指定其成員的大小,這個值被隱式地定義成int。