天天看點

《21天學通C++(第7版)》——17.2 典型的vector操作

本節書摘來自異步社群出版社《21天學通c++(第7版)》一書中的第17章,第17.2節,作者: 【美】siddhartha rao, 【德】nicolai m. josuttis,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。

21天學通c++(第7版)

std::vector類的行為規範和公有成員是由c++标準定義的,是以,遵循該标準的所有c++程式設計平台都支援本章将介紹的vector操作。

vector是一個模闆類,需要使用第14章介紹的方法進行執行個體化。要執行個體化vector,需要指定要在該動态數組中存儲的對象類型:

《21天學通C++(第7版)》——17.2 典型的vector操作

要聲明指向list中元素的疊代器,可以這樣做:

《21天學通C++(第7版)》——17.2 典型的vector操作

如果需要可用于修改值或調用非const函數的疊代器,可使用iterator代替const_iterator。

鑒于std::vector有多個重載的構造函數,您可在執行個體化vector時指定它開始應包含的元素數以及這些元素的初始值,還可使用vector的一部分來執行個體化另一個vector。

程式清單17.1示範了幾種執行個體化vector的方式。

程式清單17.1 各種執行個體化std::vector的方式:指定長度和初始值以及複制另一個vector中的值

《21天學通C++(第7版)》——17.2 典型的vector操作

分析:

上述代碼示範了如何為整型具體化vector類,即執行個體化一個存儲整型資料的vector。該vector名為vecintegers,它使用了預設構造函數。在不知道容器最小需要多大,即不知道要存儲多少個整數時,預設構造函數很有用。執行個體化vector的第2種和第3種方式如第10行和第13行所示,在這裡,程式員知道vector至少應包含10個元素。注意,這并沒有限制容器最終的大小,而隻是設定了初始大小。第4種形式如第16行和第18行所示,它使用一個vector執行個體化另一個vector的内容,即複制vector對象或其一部分。這是所有stl容器都支援的構造函數。最後一種形式是使用疊代器。vecsomeelementcopied包含vecwithtenelements的前5個元素。

第4個構造函數隻能用于類型類似的對象,是以可使用一個包含整型對象的vector來執行個體化vecarraycopy——另一個整型vector,但如果其中一個vector包含的對象類型為float,代碼将不能通過編譯。

cbegin()和cend()是否導緻編譯錯誤?

如果您使用的編譯器沒有遵循c++11标準,請使用begin()和end()分别代替該程式中的cbegin()和cend()。

cbegin()和cend()的不同之處(優點)在于,它們傳回一個疊代器,但較老的編譯器不支援它們。

17.2.2 使用push_back()在末尾插入元素

執行個體化一個整型vector後,接下來需要在vector中插入元素(整數)。在vector中插入元素時,元素将插入到數組末尾,這是使用成員方法push_back完成的:

《21天學通C++(第7版)》——17.2 典型的vector操作

程式清單17.2示範了如何使用push_back()在std::vector中動态地添加元素。

程式清單17.2 使用push_back在vector中插入元素

《21天學通C++(第7版)》——17.2 典型的vector操作

輸出:

.

《21天學通C++(第7版)》——17.2 典型的vector操作

第9~12行的push_back是vector類的一個公有成員方法,用于在動态數組末尾插入對象。請注意函數size ()的用法,它傳回vector中存儲的元素數。

c++11

初始化清單

c++11通過std::initialize_list<>支援初始化清單,讓您能夠像處理靜态數組那樣,在執行個體化vector的同時初始化其元素:

《21天學通C++(第7版)》——17.2 典型的vector操作

如果在程式清單17.2中使用這種文法,可節省3行代碼,但這裡沒有這樣做,因為編寫本書時,microsoft visual c++ 2010編譯器的std::vector實作不支援初始化清單。

push_back在vector末尾插入元素。如果要在中間插入元素,該如何辦呢?很多stl容器(包括std::vector)都包含insert()函數,且有多個重載版本。

其中一個版本讓您能夠指定插入位置:

《21天學通C++(第7版)》——17.2 典型的vector操作

另一個版本讓您能夠指定插入位置、要插入的元素數以及這些元素的值(都相同):

《21天學通C++(第7版)》——17.2 典型的vector操作

還可将另一個vector的内容插入到指定位置:

《21天學通C++(第7版)》——17.2 典型的vector操作

可使用疊代器(通常是由begin()或end()傳回的)告訴insert()您想将新元素插入到什麼位置。

也可将該疊代器設定為stl算法(如std::find()函數)的傳回值。std::find()可用于查找元素,然後在這個位置插入另一個元素(這将導緻查找的元素向後移)。

程式清單17.3示範了vector::insert()的各種重載版本。

程式清單17.3 使用函數vector::insert在指定位置插入元素

《21天學通C++(第7版)》——17.2 典型的vector操作
《21天學通C++(第7版)》——17.2 典型的vector操作

上述代碼示範了insert函數的強大功能,它讓您能夠将值插入到容器中間。第17行的vector包含4個元素,每個元素都被初始化為90;然後,使用了成員函數vector::insert的各種重載版本。第23行在開頭添加了一個元素;第26行在末尾添加了兩個元素,它們的值都是45。第35行示範了如何将一個vector的元素插入到另一個vector中間(這裡是第一個元素後面,偏移量為1)。

雖然函數vector::insert功能衆多,但給vector添加元素時,應首選push_back()。

請注意,将元素插入vector時,insert()可能是效率最低的(插入位置不是末尾時),因為在開頭或中間插入元素時,将導緻vector類将後面的所有元素後移(為要插入的元素騰出空間)。根據容器中包含的對象類型,這種移動操作可能需要調用複制構造函數或指派運算符,是以開銷可能很大。在上述例子中,vector包含的是int對象,移動開銷不是很大。但在其他情況下,情況可能并非如此。

如果需要頻繁地在容器中間插入元素,應選擇使用第18章将介紹的std::list。

您使用的c++編譯器是否較老

在程式清單17.3中,函數displayvector()使用了c++11關鍵字auto來聲明疊代器的類型,如第6行所示。對于這個示例以及後面的示例,如果要使用非c++11編譯器編譯它們,需要将auto替換為顯式類型,這裡為vector::const_iterator。

是以,如果您使用的是較老的編譯器,需要将displayvector()修改成下面這樣:

《21天學通C++(第7版)》——17.2 典型的vector操作

可使用下列方法通路vector的元素:使用下标運算符([])以數組文法方式通路;使用成員函數at();使用疊代器。

程式清單17.1示範了如何建立一個包含10個元素的vector執行個體:

《21天學通C++(第7版)》——17.2 典型的vector操作

可使用類似于數組的文法通路并設定各個元素:

《21天學通C++(第7版)》——17.2 典型的vector操作

程式清單17.4示範了如何使用下标運算符([])通路元素。

程式清單17.4 使用數組文法通路vector中的元素

《21天學通C++(第7版)》——17.2 典型的vector操作
《21天學通C++(第7版)》——17.2 典型的vector操作

在第17、21和23行,像使用靜态數組那樣,使用下标運算符([])通路并設定了vector的元素。下标運算符接受一個從零開始的元素索引,與靜态數組一樣。注意到第15行的for循環将索引與vector::size()進行比較,確定它跨越vector的邊界。

使用[]通路vector的元素時,面臨的風險與通路數組元素相同,即不能超出容器的邊界。使用下标運算符([ ])通路vector的元素時,如果指定的位置超出了邊界,結果将是不确定的(什麼情況都可能發生,很可能是通路違規)。

更安全的方法是使用成員函數at():

《21天學通C++(第7版)》——17.2 典型的vector操作

at()函數在運作階段檢查容器的大小,如果索引超出邊界(無論如何都不能這樣做),将引發異常。

下标運算符([ ])隻有在保證邊界完整性的情況下才是安全的,如前一個例子所示

17.2.5 使用指針文法通路vector中的元素

也可使用疊代器以類似于指針的文法通路vector中的元素,如程式清單17.5所示。

程式清單17.5 使用指針文法(疊代器)通路vector中的元素

《21天學通C++(第7版)》——17.2 典型的vector操作
《21天學通C++(第7版)》——17.2 典型的vector操作

在這個例子中,疊代器有點像指針,疊代器的用法很像指針算術運算,如第25和29行所示。在第25行,使用了解除引用運算符(*)來通路存儲在vector中的值,而第29行使用了運算符++遞增疊代器,使其指向下一個元素。第21行使用了std::distance來計算元素的偏移量(相對于開頭的位置),這是根據begin()和指向元素的疊代器計算得到的。

除支援使用push_back方法在末尾插入元素外,vector還支援使用pop_back函數将末尾的元素删除。使用pop_back将元素從vector中删除所需的時間是固定的,即不随vector存儲的元素個數而異。程式清單17.6示範了如何使用函數pop_back删除vector末尾的元素。

程式清單17.6 使用pop_back删除最後一個元素

《21天學通C++(第7版)》——17.2 典型的vector操作
《21天學通C++(第7版)》——17.2 典型的vector操作

上述輸出表明,第29行的pop_back函數将vector的最後一個元素删除,進而減少了vector包含的元素數。第32行再次調用size(),以證明vector包含的元素少了一個,如輸出所示。

在程式清單17.3中,displayvector()隻能接受整型vector作為參數,而在程式清單17.6中,它是個模闆函數(第4-13行)。這有助于将該模闆函數重用于浮點型vector:

《21天學通C++(第7版)》——17.2 典型的vector操作

該模闆函數接受任何類型的vector作為參數,隻要該類型支援運算符,且其傳回值可被cout了解。*

本文僅用于學習和交流目的,不代表異步社群觀點。非商業轉載請注明作譯者、出處,并保留本文的原始連結。

繼續閱讀