欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中std::vector的6種初始化方式

 更新時(shí)間:2023年08月07日 09:41:42   作者:吃素的施子  
這篇文章主要介紹了C++中std::vector的6種初始化方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

C++ std::vector的6種初始化

1.vector<int> list1; 默認(rèn)初始化,最常用

此時(shí),vector為空, size為0,表明容器中沒有元素,而且 capacity 也返回 0,意味著還沒有分配內(nèi)存空間。 這種初始化方式適用于元素個(gè)數(shù)未知,需要在程序中動(dòng)態(tài)添加的情況。

2.vector<int> list2(list); 或者 vector<int> ilist2 = ilist; //拷貝初始化 ,"="

兩種方式等價(jià) , list2 初始化為list 的拷貝, list必須與list2 類型相同, 也就是同為int的vector類型, ilist2將具有和ilist相同的容量和元素

3.vector<int> list = {1,2,3.0,4,5,6,7};

vector<int> list {1,2,3.0,4,5,6,7};//列表中元素的拷貝 ilist 初始化為列表中元素的拷貝,列表中元素必須與ilist的元素類型相容, 本例中必須是與整數(shù)類型相容的類型,整形會(huì)直接拷貝,其他類型會(huì)進(jìn)行類型轉(zhuǎn)換。

4.vector<int> list3(list.begin()+2, list.end()-1); //比較常用

將points數(shù)組轉(zhuǎn)換成vector; 挺好用的; list3初始化為兩個(gè)迭代器指定范圍中元素的拷貝,范圍中的元素類型必須與list3 的元素類型相容, 在本例中ilist3被初始化為{3,4,5,6}。

注意:由于只要求范圍中的元素類型與待初始化的容器的元素類型相容,因此迭代器來自不同的容器是可能的,

例如,用一個(gè)double的list的范圍來初始化ilist3是可行的。另外由于構(gòu)造函數(shù)只是讀取范圍中的元素進(jìn)行拷貝,因此使用普通迭代器還是const迭代器來指出范圍并沒有區(qū)別。

這種初始化方法特別適合于獲取一個(gè)序列的子序列。

5.vector<int> ilist4(7); ilist4中將包含7個(gè)元素

默認(rèn)值初始化,ilist4中將包含7個(gè)元素,每個(gè)元素進(jìn)行缺省的值初始化, 對于int,也就是被賦值為0,因此ilist4被初始化為包含7個(gè)0。

當(dāng)程序運(yùn)行初期元素大致數(shù)量可預(yù)知,而元素的值需要?jiǎng)討B(tài)獲取的時(shí)候, 可采用這種初始化方式。  

6.vector<int> ilist5(7,3);

指定值初始化,ilist5被初始化為包含7個(gè)值為3的int; 這個(gè)也比較常用。

std::vector使用總結(jié)

Vector

Vector描述的是一個(gè)動(dòng)態(tài)數(shù)組(dynamic array),并提供了相關(guān)操作和接口。

在這里插入圖片描述

在使用Vector之前,需要引入頭文件#include<vector>,在此頭文件中,類型vector是一個(gè)定義于namespace std內(nèi)的template

template<
    class T,
    class Allocator = std::allocator<T>
> class vector;

其中T可以是任意類型,Allocator用來定義內(nèi)存模型,默認(rèn)是C++標(biāo)準(zhǔn)庫提供的allocator

Vector的能力

Vector將元素復(fù)制到dynamic array內(nèi)部,是一種動(dòng)態(tài)的順序表結(jié)構(gòu)。Vector支持隨機(jī)訪問,可以以常量時(shí)間訪問元素,Vector支持隨機(jī)訪問迭代器,以及STL提供的任何算法(排序、查找等)。

但對于插入、刪除和移動(dòng)等操作,Vector效率較低(類似于數(shù)組的特性)。

大?。╯ize)和容量(capacity)

vector區(qū)別于一般數(shù)組的特性之一就是能夠動(dòng)態(tài)的“擴(kuò)容”,在容量能夠容納所有元素的前提下,提供基于pointer、reference、iterator的訪問,以及元素的操作等,因此,大小和容量的概念至關(guān)重要。  

Vector的大?。╯ize)是指當(dāng)前元素所占用空間,而容量(capacity)則是指vector分配內(nèi)存預(yù)留大小,當(dāng)size超過capacity時(shí),vector會(huì)自動(dòng)進(jìn)行擴(kuò)容,重新分配內(nèi)存。

舉個(gè)例子——

vector<int> v;
	for (int i=0; i < 20; i++) {
		v.push_back(i);
		cout<<"i = "<<i
			<< " size = " << v.size()
			<< " capacity = " << v.capacity() << endl;
	}

在這里插入圖片描述

可以看出,vector的大小是隨著插入元素不斷增加的,也就是說,size()的作用其實(shí)和sizeof的作用類似,但是由于vector都是reference語義的操作,sizeof一個(gè)vector對象,無法得到實(shí)際大小,所以vector提供了size成員函數(shù)。而capacity()則反映了vector的動(dòng)態(tài)擴(kuò)容機(jī)制。

vector容量的概念之所以重要,有兩個(gè)原因——  

1.一旦內(nèi)存重新分配,vector相關(guān)元素的所有reference、pointer、iterator都會(huì)失效。這里的失效是指,原來的值需要更新到重新分配后的內(nèi)存地址。

2.內(nèi)存的重新分配需要一定時(shí)間。

reserve函數(shù)

通過reserve函數(shù)可以顯式的指定預(yù)留空間的大小,而避免vector反復(fù)的進(jìn)行內(nèi)存重新分配, 從而提高vector的使用效率。但reserve不能減小vector容量,比如,已存在vector.capacity = 100,使用reserve(80)不會(huì)有任何作用。

vector<int> v(100);
	cout<<v.size()<<" "<<v.capacity()<<endl;
	v.reserve(80);
	cout<<v.size()<<" "<<v.capacity()<<endl;

在這里插入圖片描述

此外,還可以通過vector的構(gòu)造函數(shù)顯式的指定容量大小,比如:

vector<int> v(100);

使用這種方法的時(shí)候,vector會(huì)調(diào)用元素的default構(gòu)造函數(shù)進(jìn)行初始化,對于基礎(chǔ)類型,vector會(huì)進(jìn)行零值初始化(類似于Java的初始化機(jī)制),比如說——

class test{
	static int count;
public:
	test(){
		count++;
		cout<<"test constructor function:"<<count<<endl;
	}
};
int test::count = 0;
int main(){
	vector<test> v(10);// 調(diào)用10次test默認(rèn)構(gòu)造函數(shù)	
	return 0;
} 

在這里插入圖片描述

這種方法可能會(huì)頻繁調(diào)用構(gòu)造函數(shù),因此效率不如reverse的高。

shrink_to_fit函數(shù)

reverse函數(shù)無法縮減容量,但是很多時(shí)候,vector自動(dòng)擴(kuò)容機(jī)制分配的內(nèi)存往往是多余的,如果頻繁使用vector的話,這種內(nèi)存浪費(fèi)會(huì)相當(dāng)可觀。

C++11提供了縮減容量以符合當(dāng)前需求的函數(shù),shrink_to_fit函數(shù)。

該函數(shù)不具有強(qiáng)制力的要求,換言之,具體實(shí)現(xiàn)可能會(huì)因編譯器實(shí)現(xiàn)而不同。

但大多數(shù)情況下,縮減容量是有效的,比如——

vector<int> v;
	cout<<"capacity = "<<v.capacity()<<endl;
	v.reserve(10);
	cout<<"capacity = "<<v.capacity()<<endl;
	v.shrink_to_fit();
	cout<<"capacity = "<<v.capacity()<<endl;

在這里插入圖片描述

Vector操作

構(gòu)造函數(shù)、析構(gòu)函數(shù)

vector的構(gòu)造函數(shù)和析構(gòu)函數(shù)如下表所示——

序號(hào)操作效果
1vector<Elem> cDefault構(gòu)造函數(shù),產(chǎn)生一個(gè)vector,沒有任何元素
2vector<Elem>c(c2)vector<Elem>c=c2Copy構(gòu)造函數(shù),建立c2同型vector并成為c2的一份副本,該復(fù)制是深度復(fù)制
3vector<Elem>c(rv)vector<Elem>c=rvrv是一個(gè)vector右值引用,那么這里的構(gòu)造函數(shù)是一個(gè)Move構(gòu)造函數(shù),建立一個(gè)新的vector,取右值內(nèi)容(C++11新特性)
4vector<Elem>c(n)利用元素的默認(rèn)構(gòu)造函數(shù)生成一個(gè)大小為n(容量也為n)的vector
5vector<Elem>c(n,elem)建立一個(gè)大小為n的vector,并初始化為elem
6vector<Elem>c(beg,end)建立一個(gè)vector,并以迭代器所指向的區(qū)間[beg,end)作為元素值
7vector<Elem>c(initlist)vector<Elem>c=initlist建立一個(gè)vector,以初值列initlist元素為初值(C++11新特性)
8c.~vector()銷毀所有元素,釋放內(nèi)存

其中3和7是C++11新特性,6是基于迭代器的,第一次見可能會(huì)比較陌生,但使用起來很方便,比如——

vector<int> v{ 1,2,3,4,5,6,7,8,9 };// initlist初始化
	vector<int> v2(v.begin(), v.end());// 基于迭代器的初始化
	vector<int> v3 = move(v2); // Move構(gòu)造函數(shù)
	for (const auto&elem : v3) // range-based for循環(huán)
	{
		cout << elem << " ";
	}

在這里插入圖片描述

非更易型操作(Nonmodifying Operating)

STL中有非更易的概念,即不改變?nèi)萜鲀?nèi)元素.

序號(hào)操作效果
1c.empty()容器為空返回true,不為空返回false,相當(dāng)于size()==0
2c.size()返回當(dāng)前元素的個(gè)數(shù)
3c.max_size()返回元素個(gè)數(shù)之最大可能量
4c.capacity()返回容器當(dāng)前最大容量
5c.reserve(n)如果容器不足,顯示擴(kuò)容,該操作會(huì)引起迭代器、指針、引用的失效,但并未改變元素的值,因此仍舊視為非更易型操作
6c.shrink_to_fit()降低容量,使得size()==capacity(),(C++11新特性)
7c1==c2對每個(gè)元素調(diào)用c1==c2,全部相等返回true
8c1!=c2只要有一個(gè)元素相等,返回true,相當(dāng)于!(c1==c2)
9c1>c2,c1>=c2,c1<c2,c1<=c2同上,依次類推

賦值操作(Assignment Operating)

賦值操作可能會(huì)引起元素的默認(rèn)構(gòu)造函數(shù)、復(fù)制構(gòu)造函數(shù)、賦值操作符等,詳細(xì)如下表——

序號(hào)操作效果
1c1=c2把c2的全部元素賦值給c
2c=rv將rvalue 右值引用以 move assignment的方式賦值給c(C++11新特性
3c = initlist將初值列initlist的所有元素賦值給c(C++11新特性)
4c.assign(n,elem)復(fù)制n個(gè)elem,賦值給c
5c.assign(beg,end)復(fù)制迭代器指向區(qū)間[beg,end)內(nèi)容,賦值給c
6c.assign(initlist)將初值列initlist的所有元素賦值給c
7c.swap(c2)置換c和c2的數(shù)據(jù)
8swap(c1,c2)置換c1和c2的數(shù)據(jù)

元素訪問(Element Access)

下表列出了所有訪問vector元素的方法,對于所有non-const元素,返回的都是元素的reference,這些操作中,只有at()會(huì)檢查邊界,如果越界,拋出out_of_range異常。——

序號(hào)操作效果
1c[index]返回索引index所指向的元素
2c.at(index)返回index所指向的元素(會(huì)進(jìn)行邊界檢查)
3c.front()返回第一個(gè)元素(不會(huì)檢查第一元素是否存在)
4c.back()返回最后一個(gè)元素(不會(huì)檢查最后一個(gè)元素是否存在)

由于vector只提供了at函數(shù)的檢查元素,所以對于越界或者訪問空元素的情況,其結(jié)果是未定義的,視編譯器而異。

Visual Studio比較嚴(yán)格,將此行為定義為運(yùn)行時(shí)異常,而GCC則較為寬松,允許這一非法操作。

vector<int> v{ 1,2,3,4,5,6,7,8,9 };
	v.clear();
	cout << v.front() << endl;// Expression:front() called on empty vector.
	cout<< v[10]<<endl;// Expression:vector subscript out of range.

在這里插入圖片描述

迭代器函數(shù)(Iterator Function)

vector支持隨機(jī)訪問(random access)迭代器,理論上STL提供的所有迭代器都能為其所用。

迭代器是STL提供操作容器的重要工具,熟練使用迭代器能夠?qū)TL各大容器的性能發(fā)揮到極致。

序號(hào)操作效果
1c.begin()返回一個(gè)randrom access iterator指向第一個(gè)元素
2c.end()返回一個(gè)random access iterator指向的之后一個(gè)元素
3c.cbegin()返回一個(gè)const random access iterator指向的第一個(gè)元素(C++11新特性
4c.cend()返回一個(gè)const random access iterator指向的最后一個(gè)元素(C++11新特性
5c.rbegin()返回一個(gè)反向迭代器(reverse iterator)指向的第一個(gè)元素
6c.rend()返回一個(gè)reverse iterator指向的最后一個(gè)元素
7c.crbegin()返回一個(gè)const reverse iterator指向的第一個(gè)元素(C++新特性
8c.crend()返回一個(gè)const reverse iterator指向的最后一個(gè)元素(C++11新特性

迭代器結(jié)合auto以及range-based for循環(huán),能夠?qū)⒃氐脑L問以一種清新脫俗的方式展現(xiàn)出來——

vector<int> v{ 1,2,3,4,5,6,7,8,9 };
	for (auto it = v.cbegin(); it != v.cend();++it) {
		cout << *it << " ";
	}

在這里插入圖片描述

再比如說容器元素的逆序輸出——

vector<int> v{ 1,2,3,4,5,6,7,8,9 };
	for (auto it = v.crbegin(); it != v.crend();++it) {
		cout << *it << " ";
	}

在這里插入圖片描述

插入和移除(Inserting and Removing)

插入和移除無疑是最常用的操作,掌握了這些,基本上就可以使容器在自己的代碼中產(chǎn)生戰(zhàn)斗力——

序號(hào)操作效果
1c.push_back(elem)在vector末尾插入元素elem
2c.pop_back()移除最后一個(gè)元素,但是不返回該元素
3c.insert(pos,elem)在iterator指向的pos位置的前方插入一個(gè)元素elem的副本,并返回新元素的位置(此時(shí)返回的是整型,而非iterator)
4c.insert(pos,n,elem)在iterator指向的pos位置的前方插入n個(gè)元素的副本,并返回第一個(gè)新元素的位置
5c.insert(pos,beg,end)在iterator指向的pos位置的前方插入?yún)^(qū)間[beg,end)內(nèi)所有元素的副本,并返回第一個(gè)新元素的位置
6c.insert(pos,initlist)在iterator指向的pos位置的前方插入初始化列表所有元素的副本,并返回第一個(gè)元素的位置(C++11新特性
7c.emplace(pos,args…)在iterator指向的pos位置的前方插入一個(gè)以args為初值的元素,并返回新元素的位置(C++11新特性
8c.emplace_back(args…)在vector末尾附加一個(gè)args為初值的元素,不返回任何東西
9c.erase(pos)移除iterator位置pos上的元素,返回下一個(gè)元素的位置
10c.erase(beg,end)移除區(qū)間[beg,end)所指向的元素所有內(nèi)容,返回下一個(gè)元素的位置
11c.resize(num)將vector大小調(diào)整為num,若大小增大,新元素以默認(rèn)構(gòu)造函數(shù)或者零值進(jìn)行初始化
12c.resize(num,elem)將vector大小調(diào)整為num,若大小增大,新元素以elem進(jìn)行初始化
13c.clear()移除所有元素,容器清空

我們演示一個(gè)插入到刪除的過程——

vector<int>v;
	vector<int>v2{ -1,-2,-3,-4 };
	cout << "Source data:";
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}
	for (const auto&elem : v) {
		cout << elem << " ";
	}
	cout << endl << "insert vector 2:";
	v.insert(v.end(), v2.begin(), v2.end());
	for (const auto&elem : v) {
		cout << elem << " ";
	}
	cout << endl << "remove vector 2:";
	auto begin_it = v.begin();
	while (*begin_it != *v2.begin()) {
		begin_it++;
	}
	v.erase(begin_it, v.end());
	for (const auto&elem : v) {
		cout << elem << " ";
	}

在這里插入圖片描述

異常處理

vector僅支持最低限度的邏輯差錯(cuò)檢查,Subscript操作符的安全版本at()是唯一一個(gè)被C++ standard認(rèn)可得以拋出異常的函數(shù),此外C++ standard 同時(shí)規(guī)定,只有一般標(biāo)準(zhǔn)異?;蛘弑挥脩糇远x的異常才可能發(fā)生,也就是說,vector的一些非法操作,在運(yùn)行時(shí)都不會(huì)拋出異常,但程序員需要對自己的非法操作負(fù)責(zé)。

1. 如果push_back安插元素時(shí)發(fā)生異常,函數(shù)不產(chǎn)生效用;

2. 如果元素remove/copy操作不拋出異常, 那么insert/emplace等要么成功,要么不拋出異常;

3. pop_back絕對不會(huì)拋出任何異常;

4. 如果元素remove/copy操作不拋出異常,erase也不會(huì)拋出異常;

5. swap和clear不會(huì)拋出異常;

6. 如果元素remove/copy操作不拋出異常,那么所有的操作不是成功,就是不產(chǎn)生任何效果,包括不拋出異常。

以上所有都基于“析構(gòu)函數(shù)不得拋出任何異常”的前提。但實(shí)際上,編譯器會(huì)做不同程度的優(yōu)化,比如熱心的VS,幾乎在所有vector可能出現(xiàn)的異常檢測上都做了處理,在C++ Standard未定義的部分做了諸多工作。

這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論