C++ Primer 筆記-第9章 順序容器

9.1 順序容器(sequential container)概述
vector
:可變大小數(shù)組,deque
:雙端隊列,list
:雙向鏈表,forward_list
:單向鏈表,array
:固定大小數(shù)組,string
:專門用于保存字符的可變大小容器。與內(nèi)置數(shù)組相比,
array
?是一種更安全、更容易使用的數(shù)組類型。forward_list
?沒有?size
?操作,因為保存和計算其大小就會比手寫鏈表多出額外的開銷。

9.2 容器庫概覽
反向容器的額外成員(不支持?
forward_list
)

reverse_iterator ? ? ? ?// 按逆序?qū)ぶ吩氐牡?/span>
const_reverse_iterator ?// 不能修改元素的逆序迭代器
c.rbegin(), c.rend() ? ?// 返回指向c的尾元素和首元素之前位置的迭代器
c.crbegin(), c.crend() ?// 返回 const_reverse_iterator

9.2.1 迭代器
forward_list
?迭代器不支持遞減運算符(--)。
9.2.2 容器類型成員
通過?類型別名?我們可以在不了解容器中元素類型的情況下使用它。
9.2.4 容器定義和初始化
當(dāng)傳遞迭代器參數(shù)來拷貝一個范圍時,就不要求新容器和原容器的類型是相同的了,只要能將要拷貝的元素轉(zhuǎn)換為要初始化的容器的元素類型即可。
只有順序容器的構(gòu)造函數(shù)才接受大小參數(shù),關(guān)聯(lián)容器并不支持。
我們不能對內(nèi)置數(shù)組欸寫進行拷貝或者對象賦值操作,但是?
array
?并無此限制。array
?要求初始值的類型必須與要創(chuàng)建的容器大小和類型均相同。
9.2.5 賦值和?swap
由于右邊運算對象的大小可能與左邊運算對象的大小不同,因此?
array
?類型不支持?assign
,也不允許用花括號包圍的值列表進行賦值。除?
array
?外,swap
?交換兩個容器內(nèi)容的操作元素本身并未交換,只是交換了兩個容器的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。與其他容器不同,?
swap
?兩個?array
?會真正的交換它們的元素。因此,指針、引用和迭代器所綁定的元素保持不變,但是元素值已經(jīng)與另一個?array
?中對應(yīng)元素的值進行了交換。(指向的內(nèi)存地址沒變,內(nèi)存里的內(nèi)容調(diào)換了)。

// 例如:假定iter在swap之前指向svec1[0]的元素a
array<string, 1> svec1 = { "a" }, svec2 = { "b" };
auto iter = svec1.begin();
swap(svec1, svec2);
// 那么在swap之后它還是指向svec1[0]的元素,但是元素值變成了 b
iter == svec1.begin(); ?// true
&iter == "b"; ? ? ? ? ? // true

除?
string
?外,指向容器的迭代器、引用和指針在?swap
?操作之后都不會失效。它們?nèi)灾赶?swap
?操作之前所指的那些元素?(指向的內(nèi)存地址調(diào)換了,內(nèi)存里的內(nèi)容沒換)。

// 例如:假定iter在swap之前指向svec1[0]的元素a
vector<string> svec1 = { "a" }, svec2 = { "b" };
auto iter = svec1.begin();
swap(svec1, svec2);
// 那么在swap之后它指向svec2[0]的元素,且元素值還是a。
iter == svec2.begin(); ?// true
&iter == "a"; ? ? ? ? ? // true

與其他容器不同,對一個?
string
?調(diào)用?swap
?會導(dǎo)致迭代器、引用和指針失效。非成員版本的?
swap
?在泛型編程中是非常重要的。統(tǒng)一使用非成員版本的?swap
?是一個好習(xí)慣。
9.2.7 關(guān)系運算符
只有當(dāng)其元素類型定義了相應(yīng)的比較運算符時,才能使用關(guān)系運算符來比較兩個容器。

9.3 順序容器操作
9.3.1 向順序容器添加元素
forward_list
?有自己專有版本的?insert
?和?emplace
;且不支持?push_back
?和?emplace_back
。vector
?和?string
?不支持?push_front
?和?emplace_front
。insert
?函數(shù)將元素插入到迭代器所指定的位置之前。emplace
?函數(shù)在容器中直接構(gòu)造元素。傳遞給?emplace
函數(shù)的參數(shù)必須與元素類型的構(gòu)造函數(shù)想匹配。
9.3.2 訪問元素

vector<int> c = { 1 };
auto& v1 = c.back(); ? ? // 獲得指向最后一個元素的引用
auto v2 = c.back(); ? ? ?// 獲得最后一個元素的拷貝

9.3.3 刪除元素
刪除?
deque
?中除首尾位置之外的任何元素都會使所有迭代器、引用和指針失效。指向?
vector
?或?string
?中刪除點之后位置的迭代器、引用和指針都會失效。pop_front
?和?pop_back
?操作返回?void
。
9.3.4 特殊的?forward_list
?操作
在一個單向鏈表中沒有簡單的方法來獲取一個元素的前驅(qū)。出于這個原因,在一個?
forward_list
?中添加和刪除元素的操作是通過改變給定元素之后的元素來完成的。于是定義了?insert_after
、emplace_after
?和?erase_after
?操作與普通順序容器里的?insert
、emplace
?和?erase
?操作相對應(yīng)。before_begin()
?返回指向鏈表首元素之前不存在的元素的迭代器。首前迭代器(off_the_beginning iterator)不能解引用。
9.3.5 改變?nèi)萜鞔笮?/h1>對?vector
、string
?或?deque
?進行?resize
?可能導(dǎo)致迭代器、指針和引用失效。
9.3.6 容器操作可能使迭代器失效
對于?deque
,如果在首尾位置添加元素,迭代器會失效,但指向存在的元素的引用和指針不會失效。
當(dāng)我們添加/刪除?vector
?或?string
?的元素后,或在?deque
?中首元素之外任何位置添加/刪除元素后,原來?end
?返回的迭代器總是會失效,所以不要緩存?end
?返回的迭代器。

9.4?vector
?對象是如何增長的
調(diào)用?reserve
?不會減少容器占用的內(nèi)存空間。調(diào)用?resize
?只改變?nèi)萜髦性氐臄?shù)目,而不是容器的容量,也不能減少容器預(yù)留的內(nèi)存空間。
調(diào)用?shrink_to_fit
?來要求?deque
、vector
?或?string
?退回不需要的內(nèi)存空間。但是不能保證調(diào)用該函數(shù)后一定會退回多余的內(nèi)存空間。

9.5 額外的?string
?操作
9.5.1 構(gòu)造?string
?的其他方法
當(dāng)我們從一個?const char*
?創(chuàng)建?string
?時,如果未傳遞計數(shù)值且數(shù)組也未以空字符結(jié)尾,或者給定計數(shù)值大于數(shù)組大小,則構(gòu)造函數(shù)的行為是未定義的。
s.substr(pos, n)
?返回一個?string
,包含?s
?中從?pos
?開始的?n
?個字符的拷貝。
9.5.2 改變?string
?的其他方法
assgin
?和?append
?函數(shù)無須指定要替換?string
?中哪個部分:assgin
?總是替換所有內(nèi)容,append
?總是將新字符追加到末尾。
replace
?函數(shù)提供了兩種指定刪除元素范圍的方式:可以通過一個位置和一個長度來指定范圍,也可以通過一個迭代器范圍來指定。
insert
?函數(shù)允許兩種方式指定插入點:用一個下標(biāo)或一個迭代器。元素都會插入到給定下標(biāo)(或迭代器)之前的位置。
9.5.3?string
?搜索操作
如果搜索失敗,返回一個名為?string::npos
?的?static
?成員,標(biāo)準(zhǔn)庫將?npos
?定義為一個?const string::size_type
?類型。
搜索是?大小寫敏感?的。
9.5.5 數(shù)值轉(zhuǎn)換
如果?string
?不能轉(zhuǎn)換為一個數(shù)值,這些函數(shù)拋出一個?invalid_argument
?異常,如果轉(zhuǎn)換得到的數(shù)值無法用任何類型來表示,則拋出一個?out_of_range
?異常。

9.6 容器適配器(adaptor)
適配器是標(biāo)準(zhǔn)庫中的一個通用概念。容器、迭代器和函數(shù)?都有適配器,本質(zhì)上一個適配器是一種機制,能使某種事物的行為看起來像另外一種事物一樣。
除了順序容器外,標(biāo)準(zhǔn)庫還定義了三個順序容器適配器:stack
、queue
?和?priority_queue
。

對?vector
、string
?或?deque
?進行?resize
?可能導(dǎo)致迭代器、指針和引用失效。
對于?deque
,如果在首尾位置添加元素,迭代器會失效,但指向存在的元素的引用和指針不會失效。
當(dāng)我們添加/刪除?vector
?或?string
?的元素后,或在?deque
?中首元素之外任何位置添加/刪除元素后,原來?end
?返回的迭代器總是會失效,所以不要緩存?end
?返回的迭代器。

vector
?對象是如何增長的調(diào)用?reserve
?不會減少容器占用的內(nèi)存空間。調(diào)用?resize
?只改變?nèi)萜髦性氐臄?shù)目,而不是容器的容量,也不能減少容器預(yù)留的內(nèi)存空間。
調(diào)用?shrink_to_fit
?來要求?deque
、vector
?或?string
?退回不需要的內(nèi)存空間。但是不能保證調(diào)用該函數(shù)后一定會退回多余的內(nèi)存空間。

string
?操作string
?的其他方法當(dāng)我們從一個?const char*
?創(chuàng)建?string
?時,如果未傳遞計數(shù)值且數(shù)組也未以空字符結(jié)尾,或者給定計數(shù)值大于數(shù)組大小,則構(gòu)造函數(shù)的行為是未定義的。
s.substr(pos, n)
?返回一個?string
,包含?s
?中從?pos
?開始的?n
?個字符的拷貝。
string
?的其他方法assgin
?和?append
?函數(shù)無須指定要替換?string
?中哪個部分:assgin
?總是替換所有內(nèi)容,append
?總是將新字符追加到末尾。
replace
?函數(shù)提供了兩種指定刪除元素范圍的方式:可以通過一個位置和一個長度來指定范圍,也可以通過一個迭代器范圍來指定。
insert
?函數(shù)允許兩種方式指定插入點:用一個下標(biāo)或一個迭代器。元素都會插入到給定下標(biāo)(或迭代器)之前的位置。
string
?搜索操作如果搜索失敗,返回一個名為?string::npos
?的?static
?成員,標(biāo)準(zhǔn)庫將?npos
?定義為一個?const string::size_type
?類型。
搜索是?大小寫敏感?的。
如果?string
?不能轉(zhuǎn)換為一個數(shù)值,這些函數(shù)拋出一個?invalid_argument
?異常,如果轉(zhuǎn)換得到的數(shù)值無法用任何類型來表示,則拋出一個?out_of_range
?異常。

適配器是標(biāo)準(zhǔn)庫中的一個通用概念。容器、迭代器和函數(shù)?都有適配器,本質(zhì)上一個適配器是一種機制,能使某種事物的行為看起來像另外一種事物一樣。
除了順序容器外,標(biāo)準(zhǔn)庫還定義了三個順序容器適配器:stack
、queue
?和?priority_queue
。

// 每種容器適配器都定義兩個構(gòu)造函數(shù):默認(rèn)構(gòu)造函數(shù)創(chuàng)建一個空對象;接受一個容器的構(gòu)造函數(shù)拷貝該容器來初始化適配器。
deque<int> deq;
stack<int> stk; ? ? ? ? // 默認(rèn)構(gòu)造函數(shù)
stack<int> stk2(deq); ? // 拷貝容器內(nèi)容
// 我們可以在創(chuàng)建一個適配器時將一個命名的順序容器作為第二個類型參數(shù)來重載默認(rèn)容器類型。
vector<int> vc;
stack<int, vector<int>> vc_stk;
stack<int, vector<int>> vc_stk2(vc);

所有適配器都要求容器具有添加和刪除以及訪問尾元素的能力,因此適配器不能構(gòu)造在?
array
?和?forward_list
?之上。可以使用除?
array
?和?forward_list
?之外的任何容器類型來構(gòu)造?stack
。queue
?可以構(gòu)造于?list
?或?deque
?之上,但是不能基于?vector
?構(gòu)造。priority_queue
?可以構(gòu)造于?vector
?或?deque
?之上,但是不能基于?list
?構(gòu)造。priority_queue
?允許我們?yōu)殛犃兄械脑亟?yōu)先級。新加入的元素會排在所有優(yōu)先級比它低的已有元素之前。

