国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

STL標準模板庫 vector容器與迭代器入門

這篇具有很好參考價值的文章主要介紹了STL標準模板庫 vector容器與迭代器入門。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

STL五大件 標準模板庫

vector 就是一個連續(xù)的數(shù)據(jù) C++11 std::vector a ={1,4,2,6,7}; 可以使用花括號來定義

容器的功能就是存儲數(shù)據(jù) 迭代器的功能就是指向數(shù)據(jù),并且可以實現(xiàn)前后移動(指針)算法和容器的接口的存在

auto n = std::count_if(a.begin(),a.end(),std::bind2nd(std::less<int>),4);
count\_if 數(shù)數(shù) a.begin 指向第一個元素 迭代器類似于指針 可以++ 指向下一個元素
			   a.end指向最后一個元素的下一位
構(gòu)成一個區(qū)間 less<int>仿函數(shù)(functor) 
	int 類型的小于符號 小于int的數(shù)值 會給int類型的數(shù)比較一個大小

 bind2nd把它的第二個參數(shù)始終綁定為4 hascode <4)

allocator 分配器 用于vector第二個參數(shù) 或最后一個參數(shù) 如:
std::vector<int ,std::allcoator<int>> a ={1,4,,2,8,5,7};

STL標準模板庫 vector容器與迭代器入門

vector容器:

vector功能是長度可變的數(shù)組, 身在棧上 里面的數(shù)據(jù)存儲在堆上 因為棧不可動態(tài)擴容

vector 里面有3個指針
第一個指針是指向堆上的地址(起始地址)
第二個指針標志著結(jié)束位
第三個指針就是實際有元素的地址

vector 聲明初始化

vector是一個模板類,第一個模板參數(shù)就是數(shù)組里元素的類型
	 如:聲明一個元素是int類型的動態(tài)數(shù)組a;	vector<int> a;
	vector 可以在構(gòu)造時指定初始長度  vector(size_t n)

	例如,要創(chuàng)建一個長度為4元素為 0 的int型數(shù)組 vector<int>a(4);
	 之后可以通過 a.size()獲取數(shù)組的長度

	explicit vector(size_t n); 顯式構(gòu)造函數(shù)
	explicit vector (size_t n ,int const &val);

	vector初始化表達式的等號可以不寫
	vector<int>a  ={4,12,32,4};
	vector<int>a{4,12,32,4};	


	
	vector<int>a{4}; 代表你創(chuàng)建了一個長度為1只有一個元素4的數(shù)組。	vector(initializer_list<int>list);
	vector<int>a(4); 得到長度為4元素為0的數(shù)組	

	對于只能用花括號初始化的類成員來說就有很大問題 vector<int>a{4};  
	會得到一個長度為1只有一個元素4的數(shù)組
	struct C{
		vector<int> a = vector<int>(4);
	};
	可以用這種寫法強制調(diào)用顯示構(gòu)造函數(shù) vector<int> a = vector<int>(4); 
	得到長度為4元素為0的數(shù)組

	explicit vector (size_t n ,int const &val);
	 顯式構(gòu)造函數(shù)還可以指定第二個參數(shù),這樣就可以用0以外的值初始化整個數(shù)組了
例如:創(chuàng)建4個233組成的數(shù)組 vector<int>a(4,233);
	  等價于 vector<int> a = {233.233,233,233}

vector 容器 :push_back

void push_back(int const &val);
void push_back(int &&val); 	C++11新增
push_back函數(shù)可以在數(shù)組的末尾追加一個數(shù)。
例如: vector<int>a = {1,2}; a.push_back(3);	等價于vector<int>a = {1,2,3};	

vector 容器 :push_back的問題

int main()
{
	vector<int> a ;
	for(int i =0 ; i<100;i++)
	{
		a.push_back(i);
	}
	cout<<a<<endl;
	return 0;
}
由于不知道你會push_back多少個元素,vector的初始容量為0
 	push_back和resize一樣,每次遇到容量不足時,都會擴容2倍。
這也體現(xiàn)出了實際容量(capacity)數(shù)組大小(size)分離的好處 
當容量不足的時候就可以一次性擴容2倍,只需重新分配logn次,移動元素2N-1次
malloc是按照字節(jié)來計算 即char類型大小
	p=malloc(1000);
	q=malloc(10);
	memcpy(q,p);
	free(p);

vector容器:push_back的問題,reserve解決

int main()
{
	vector<int> a ;	
	a.reserve(100);
	for(int i =0 ; i<100;i++)
	{
		a.push_back(i); 	// i是int類型 reserver(100) 相當于400
	}
	cout<<a<<endl;
	return 0;
}
因此,如果你早知道要插入元素的數(shù)量,可以調(diào)用reserve函數(shù)先預留那么多的容量,等待接下來的推入。
這樣之后push_back時,就不會一次次地擴容兩倍慢慢成長到128 避免重新分配內(nèi)存和移動元素,更高效。
比如這里我們可以提前知道循環(huán)會執(zhí)行100次,因此reserve(100)就可以了
可以看到只有一次malloc(400),之后malloc(1024)是cout造成的	

vector容器:insert函數(shù)

	iterator insert(const_iterator pos, int const &val);
	iterator insert(const_iterator pos, int  &val);//C++11
	iteratot insert(const_iterator pos,size_t n , int const &val);  (插入位置,重復多少次,插入的值)
	iterator insert(const_iterator pos, initalizer_list<int> lst); //初始化列表對應的類型只能是initalizer_list<int> list
int main()
{
	vector<int> a ={1,2,3,4,5,6} ;	
	cout<<"a="<<a<<endl;
	 a.insert(a.begin(),233);
	cout<<"a="<<a<<endl;
	return 0;
}
	push_back可以往尾部插入數(shù)據(jù),insert可以往頭部插入數(shù)據(jù)
	insert第一個參數(shù)是插入的位置(迭代器表示)第二個參數(shù)是要插入的值。
	這個函數(shù)的復雜度為O(n),n是從插入位置pos到數(shù)組末尾end的距離,他會插入位置后方的元素整體向后移動一格,是比較低效的為了盡可能高效盡量在尾部插入元素
	如果需要高效的頭部插入,可以考慮用deque容器,他有高效的push_front函數(shù)代替,insert在容量不足時,同樣會造成重新分配以求擴容,會移動其中所有元素,這時之前保存的迭代器都會失效的。
iterator insert(const_iterator pos, int const &val);

vector容器:insert函數(shù),插到指定的元素前方

	插入到一個特定位置,可以用迭代器的加法來獲取某一位置的迭代器
	例如a.begin()+3就會指向第三個元素,那么用這個作為insert的參數(shù)就會把233這個值插回到第三個元素的位置之前。
	例如a.end()可以插入到最末尾appendd,a.end()-1則是插入到倒數(shù)第一個元素前。
	例如 a.insrt(插入的位置,重復次數(shù),插入的數(shù)據(jù));
int main()
	{
		vector<int> a ={1,2,3,4,5,6} ;	
		cout<<"a="<<a<<endl;
		a.insert(a.begin()+3,233);
		a.insert(a.end()-2,4,233);
		a.insert(a.end()-2,233);
		cout<<"a="<<a<<endl;
		return 0;
	}

vector容器:insert函數(shù),直接插入一個初始化列表

iterator insert(const_iterator pos, initalizer_list<int> lst);
insert還可以直接插入一個{}的列表!這個花括號{}形成的列表就是傳說中的初始化列表(initializer-list)是C++11新增的功能類 std::initializer_list<int>
a.insert(插入位置,{插入值1,插入值2,.....};	
這個最壞的復雜度也是O(n)并且因為其內(nèi)部預先知道了要插入列表的長度,會一次性完成擴容,比重復調(diào)用push_back重復擴容高效很多。
int main()
		{
			vector<int> a ={1,2,3,4,5,6} ;	
			cout<<"a="<<a<<endl;
			 a.insert(a.begin(),{233,666,984,221});
			cout<<"a="<<a<<endl;
			return 0;
		}

vector容器:insert函數(shù),直接插入另一個vector?

	如果你試圖用一個vector作為這個參數(shù),就會出錯!報錯會說因為vector和initializer_list不是同一個類型
	那么如何插入另一個vector,或者說,把a和b這個兩個數(shù)組合并起來呢?
int main()
	{
		vector<int> a ={1,2,3,4,5,6} ;	
		vector<int> b ={12,23,34,45,52,16} ;	
		cout<<"a="<<a<<endl;
		cout<<"b="<<b<<endl;
		 a.insert(a.begin(), b);
		cout<<"a="<<a<<endl;
		return 0;
	}

報錯信息:
STL標準模板庫 vector容器與迭代器入門

vector容器:insert函數(shù),插入另一個vector需要他的兩個迭代器

template<class It>	//這里It可以是其他容器的迭代器類型
iterator insert(const_iterator pos,It beg,It end);	

C++迭代器思想是,容器和算法之間的交互不是通過容器對象本身,而是他的迭代器
因此insert設計時就決心不支持直接接受vector做參數(shù),而是接受他的兩個迭代器組成的區(qū)間!好處有:
1.可以批量插入才能夠來自另一個不同類型的容器,例如list,只要元素類型相等,且符合迭代器規(guī)范
2. 可自由選擇對方容器的一個子區(qū)間(通過迭代器加減法)內(nèi)的元素來插入,而不是死板的只能全部插入。

  
int main()
{
	vector<int> a ={1,2,3,4,5,6} ;	
	vector<int> b ={12,23,34,45,52,16} ;	
	cout<<"a="<<a<<endl;
	cout<<"b="<<b<<endl;
	 a.insert(a.begin(), b.begin(),b.end()); //從頭部插入	會把b插入在原先a元素之前,相當于牌神的a=b+a;
	 a.insert(a.end(), b.begin(),b.end());	//從尾部插入		把b插入到a元素之后,相當于a+=b; 性能好,只要容量組后無需移動a的全部元素
	cout<<"a="<<a<<endl;
	return 0;
}

對方容器也可以是不同類型的,最底線的要求只要他的迭代器有++和*運算符即可。
例如:list::iterator

int main()
		{
			vector<int> a ={1,2,3,4,5,6} ;	
			list<int> b ={12,23,34,45,52,16} ;	
			cout<<"a="<<a<<endl;
			 a.insert(a.begin(), b.begin(),b.end()); 	//成員函數(shù)
			cout<<"a="<<a<<endl;
			return 0;
		}
		string s;
		vector<char> v;		//把一個string轉(zhuǎn)換為vector	這兩個東西里面的值是一樣的 assign接受任意迭代器作為參數(shù)	 
		v.assign(s.begin(),s.end());

vector容器:insert函數(shù),作為數(shù)據(jù)源的對方容器可以是不同類型

		template<class T>auto begin(T &&t);
		template<class T>AUTO end(T &&t);		
對方容器還可以是個C語言風格的數(shù)組,因為C語言類型沒有辦法加成員函數(shù)begin和end
	可以用std::begin和std::end這兩個全局函數(shù)代替
如果用了using namespace std 可以不寫前綴std::	還有全局函數(shù)std::size()獲取它的長度 和std::data()
這兩個函數(shù)會對于具有begin和end成員函數(shù)的容器直接調(diào)用
對于C語言數(shù)組則被特化為返回b和b+sizeof(b)/sizeof(b[0])
如果是C語言數(shù)組 	b.begin()先判斷是否合法 不合法則讓begin(b) ->b end(b)->b+szie(b);
int main()
{
	vector<int> a ={1,2,3,4,5,6} ;	
	int b[] ={12,23,34,45,52,16} ;	
	cout<<"a="<<a<<endl;
	 a.insert(a.begin(), std::b.begin(),std::b.end()); 	//成員函數(shù)
	cout<<"a="<<a<<endl;
	return 0;
}

vector 容器:構(gòu)造函數(shù)也能接受迭代器!

		template<class It>
		explicit vector(It beg,It end);		
	
		其實vector的構(gòu)造函數(shù)也接受一堆迭代器做參數(shù),來初始化其中的元素,同樣可以是不同容器的迭代器對象,只要具有++和*即可
		int main()
		{
			int b[] ={12,23,34,45,52,16} ;	
			vector<int>a(std::begin(b),std::end(b));
			cout<<"a="<<a<<endl;
			return 0;
		}

vector容器:assign函數(shù)

	template<class It>
	void assign(It beg,It end);		

	void assign(size_t n ,int const&val);

	void assign(initializer_list<int> val);
	vector<int>&operator(initializer_list<int> val);
	vector<int>&operator(vector<int>const& val);
	vector<int>&operator(vector<int> &&val);
assign這個成員函數(shù)也能夠在后期把元素覆蓋進去,和insert不同的是,他會把原來的數(shù)組完全覆蓋掉,變成一個新的數(shù)組。
a.assign(beg,end)基本和a=vector<int>(beg,end)等價,唯一的區(qū)別是后者會重新分配內(nèi)存,而前者會保留原來的容量不會釋放掉。
int main()
{
	vector<int>a={1,2,3,4,5,6} ;
	cout<<"a="<<a<<endl;
	int b[] ={12,23,34,45,52,16} ;	
	a.assign(std::begin(b).std::end(b));
	cout<<"a="<<a<<endl;
	return 0;
}
void assign(size_t n ,int const&val);這個重載,可以把vector批量填滿一個特定的值,重復的次數(shù)(度)也是參數(shù)里指定。
a.assign(n,val)基本和a=vector<int>(n,val)等價,唯一的區(qū)別是后者會重新分配內(nèi)存,而前者會保留原來的容量。
int main()
{
	vector<int>a={1,2,3,4,5,6} ;
	cout<<"a="<<a<<endl;
	a.assign(4,233);
	cout<<"a="<<a<<endl;
	return 0;
}
		void assign(initializer_list<int> val);
		vector<int>&operator(initializer_list<int> val);
		vector<int>&operator(vector<int>const& val);
		vector<int>&operator(vector<int> &&val);
assign還可以直接接受一個初始化列表作為參數(shù)
a.assign({x,y,...})和a={x,y,...}完全等價,都會保留原來的容量。
		而和a=vector<int>{x,y,....}就不等價了,這個會重新分配內(nèi)存。
int main()
		{
			vector<int>a={1,2,3,4,5,6} ; 
			cout<<"a="<<a<<endl;
			a.assign(233,666,985,211});
			cout<<"a="<<a<<endl;
			a={2 ,11};
			cout<<"a="<<a<<endl;
			cout<<"a.capacity()="<<a.capacity()<<endl;
		 	a= vector<int>{2,11};
			cout<<"a.capacity()="<<a.capacity()<<endl;
			return 0;
		}

vector 容器 :pop_back back front

void pop_back(); 
int &back();
int const &back();
int &front();
int const &front();
void pop_back(); 函數(shù)返回類型是void沒有返回值如果需要獲取刪除的值可以在pop_back之前先通過back()獲取末尾元素的值實現(xiàn)pop的效果
pop_back函數(shù)在數(shù)組的末尾刪除一個數(shù)。 只是大小  減1
例如: vector<int>a = {1,2,3}; a.pop_back(3);	等價于vector<int>a = {1,2};	

back()函數(shù)返回末尾元素的引用
a.back(); 等價于 a[a.szie()-1];
front()函數(shù)返回首個元素的引用
a.front() 	等價于 a[0];

vector 容器:erase函數(shù)

iterator erase(const_iterator pos);
erase函數(shù)可以刪除指定位置的一個元素(通過迭代器指定)	
a.erase(a.begin())就是刪除第一個元素相當于pop_front
a.erase(a.end()-1)就是刪除最后一個元素相當于pop_back
a.erase(a.begin()+2)就是刪除第三個元素 		
a.erase(a.end()-2)就是刪除倒數(shù)第二個元素
erase的復雜度最壞情況是刪除第一個元素O(n)
如果刪除的是最后一個元素則復雜度為O(1)	這是因為erase會移動pos之后的哪些元素
int main()
		{
			vector<int>a={1,2,3,4,5,6} ;
			cout<<"a="<<a<<endl;
			a.erase(a.begin()+3);
			cout<<"a="<<a<<endl;
			a.erase(a.end()-1);
			cout<<"a="<<a<<endl;
			return 0;
		}

vector 容器:erase函數(shù),批量刪除一個區(qū)間

C++里面的區(qū)間都是前面的是包含的后面是不包含的 [beg,end)

 iterator erase(const_iterator beg,const_iterator end);
erase也可以指定兩個迭代器作為參數(shù),表示把這個區(qū)間內(nèi)的對象都刪除了。

比如這里a.erase(a.begin()+1,a.begin()+3)就刪除了a的第二個和第三個元素
相當于a= a[:1]+a[3:], C++的insert和erase都是就地操作的。

例如:a.erase(a.begin()+n,a.end())就和a.resize(n)等價,前提是n小于a.size();
批量刪除的最壞復雜度依然是O(n),不過這里的兩個作為erase參數(shù)的迭代器必須是這個自己這個對象的迭代器,不是其他容器的
	 他返回刪除后最后一個元素之后那個位置的迭代器。		
int main()
		{
			vector<int>a={1,2,3,4,5,6} ;
			cout<<"a="<<a<<endl;
			a.erase(a.begin+1,a.begin()+3);	//迭代器的參數(shù) 前面必須是起始位置后面必須是終止位置
			cout<<"a="<<a<<endl;
			a.erase(a.begin+4,a.end()); //刪除5 6	相當于resize(4)			a.erase(a.begin+1,a.begin()+3);
			cout<<"a="<<a<<endl;
			cout<<"a="<<a<<endl;
			return 0;
		}

vector 容器:data()獲取首地址指針

int *data();
int const *data()
data()會返回指向數(shù)組中首個元素的指針也就等價于&a[0]
由于vector是連續(xù)存儲的數(shù)組,因此只要得到了首地址,下一個元素的地址只需要+1即可,
因為指針的p[i]相當于*(p+i),因此可以把data()返回的首地址指針當一個數(shù)組來訪問。
vector<int>a ={1,2,3,4,5,6};	int *p =a.data(); 		cout <<p[0]<< endl;
data()返回的首地址指針,配合size()返回的數(shù)組長度一起使用,(連續(xù)的動態(tài)數(shù)組只需要知道首地址和數(shù)組長度就可以確定)
用他來獲取一個C語言原始指針int * ,很方便用于調(diào)用C語言函數(shù)的和API同時還能享受vector容器RAII的安全性
vector<int>a ={1,2,3,4,5,6};
int *p =a.data();
int n = a.size();	
memset(p,-1,sizeof(int)*n);
cout <<a<< endl; 

vector容器: RAII避免內(nèi)存泄漏

vector會在離開作用域時,自動調(diào)用析構(gòu)函數(shù)釋放內(nèi)存?zhèn)兙筒槐厥謩俞尫?,能安全?

vector容器:生命周期由主對象管理

C++中運算符{}  }標志著一個語句塊的結(jié)束,在這里會調(diào)用所有身處其中的對象的析構(gòu)函數(shù)	
比如這里的vector 他的析構(gòu)函數(shù)會釋放動態(tài)數(shù)組的內(nèi)存(既自動delete)
int main(){
	int* p ;
	{
		vector<int> a ={1,2,3,4,5};
		p=a.data();
		cout<<p[0]<<endl;
		cout<<p[0]<<endl;
	}
		cout<<p[0]<<endl;	//空指針
		return 0;
}		
vector 會在退出作用域時釋放內(nèi)存,這時候所有指向其中元素的指針,包括data()都會失效
因此如果你是在語句塊內(nèi)獲取的data指針,語句塊外就無法訪問了,
可見data()指針是對vector的一種引用 實際對象生命周期仍由vector類本身管理

vector容器:延續(xù)生命周期

	int main(){
	int* p ;
	vector<int> holder;
	{
		vector<int> a ={1,2,3,4,5};
		p=a.data();
		cout<<p[0]<<endl;
		cout<<p[0]<<endl;
		holder = std::move(a); //只有移動時才是帶著指針移動 拷貝的話開辟新空間賦值數(shù)據(jù)
	}
		cout<<p[0]<<endl;	//空指針
		return 0;
}		
如果需要在一個語句塊外仍然保持data()對數(shù)組的弱引用有效,可以把語句塊內(nèi)的vector對象移動到外面的一個vector對象上
vector在移動時指針不會失效, 例如: holder = move(a);

則會把a變成空數(shù)組,holder指向原來a所包含的元素數(shù)組,且地址不變,之后即使不直接使用外面的臨時對象holder,也可以繼續(xù)提高data()指針訪問數(shù)據(jù)。

vector 容器:resize

void resize(size_t n)
void resize(size_t n ,int const &val);
除了可以在構(gòu)造函數(shù)中指定數(shù)組的大小,還可以之后再通過resize函數(shù)設置大小
適用于一開始無法指定大小的情況
vector<int>a(4)	等價于 vector<int>a;	a.resize(4);// 默認填充4個0
resize也接受第二參數(shù)的重載 ,會用這個參數(shù)的值填充所有新建的元素
vector<int>a(4,233); 	等價于	vector<int>a;	a.resize(4,233);	//填入第二參數(shù) 4次
調(diào)用resize(n)的時候,如果數(shù)組已有超過n個元素假設是m個,則他會刪除多出來的m-n個元素,前n個元素保持不變
vector<int>a]={1,2} 	a.resize(4)	等價于  vector<int>a ={1,2,0,0}
vector<int>a ={1,2,3,4,5,6};	a.resize(4) 等價于 vector<int>a ={1,2,3,4}  
調(diào)用resize(n,val)的時候,如果數(shù)組已有超過n個元素假設是m個,則第二參數(shù)val會被無視,刪除多出來的m-n個元素,前n個元素保持不變
vector<int>a]={1,2} 	a.resize(4233)	等價于  vector<int>a ={1,2,233,233}
vector<int>a ={1,2,3,4,5,6};	a.resize(4,233) 等價于 vector<int>a ={1,2,3,4} 

vector 容器:clear

void clear()
vector的clear函數(shù)可以清空該數(shù)組,也就是相當于把長度設為0 變成空數(shù)組。
例如: a.clear(); 		等價于 a.resize(0) 或a{};	
通常用于后面需要重新push_back,因此可以clear來把數(shù)組設為空。

vector 容器:clear的問題

int main(){
vector<int>a ={1,2,3,4};
cout<<"before clear,capaciy="<<a.capacity()<,endl;
a.clear();
cout<<"after clear,capaciy="<<a.capacity()<,endl;
}
clear相當于resize(0),所以他也不實際釋放掉內(nèi)存,容量(capacity)還是擺在那里
clear僅僅只是把數(shù)組大小(size)標記0而已。

vector容器: shrink_to_fit釋放多余容量

size_tshrink_to_fit();
int main()
	{
		vector<int>a={1,2,3,4,5};
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.resize(12); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reszie(4); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;

		 a.shrink_to_fit();
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		return  0; 
	}
當resize到一個更小的大小上時,多余的容量不會釋放,而是繼續(xù)保留
如擔心內(nèi)存告急可以用shrink_to_fit釋放掉多余的容量,只保留剛好為size()大小的容量。
shrink_to_fit會重新分配一段更小內(nèi)存,它同樣是會把元素移動到新內(nèi)存中,因此迭代器和指針也會失效。

vector 容器:clear的問題,shrink_to_fit解決

int main(){
vector<int>a ={1,2,3,4};
cout<<"before clear,capaciy="<<a.capacity()<,endl;
a.clear();
a.shrink_to_fit();
cout<<"after clear,capaciy="<<a.capacity()<,endl;
}
要真正釋放掉內(nèi)存,可以在clear之后在調(diào)用shrink_to_fit
				(這樣才會讓容量變成0,這時vector的data會返回nullptr)
當然,vector對象析構(gòu)時也會徹底釋放內(nèi)存,clear配合shrink_to_fit只是提前釋放

clear配合resize

resize會保留元素的1前面部分不變只在后面填充上0
如果需要把源數(shù)組前面的部分也填充上0,可以先clear再resize
vector<int>a]={1,2}; 
cout <<a << endl; 	
a.clear();	
a.resize(); 	
cout <<a << endl;

vector 容器:resize到更大尺寸會導致data失效

push_back = resize()+1; //擴容1寫入
	int main(){
	vector<int> a ={1,2,3,4,5};
	int* p=a.data();

		cout<<p[0]<<endl;
		cout<<p[0]<<endl;
		a.resize(1024);
		cout<<p[0]<<endl;	 
		return 0;
}		
當resize的目標長度大于原有的容量時,就需要重新分配一段更大的連續(xù)內(nèi)存,
并把原數(shù)組長度的部分移動過去,多出來的部分則用0來填充,這就導致了元素的地址會有所改變
從而過去data返回的指針以及所有的的迭代器對象,都會失效。 

vector 容器:resize到更小尺寸不會導致data失效

	int main(){
	vector<int> a ={1,2,3,4,5};
	int* p=a.data();	

		cout<<p[0]<<endl;
		cout<<p[0]<<endl;
		a.resize(2);
		cout<<p[0]<<endl;	 
		a.resize(5);
		return 0;
}		
當resize的目標長度小于原有的容量時,不需要重新分配一段連續(xù)的內(nèi)存,
也不會造成元素的移動(主要為了性能考慮),所以指向元素的指針不會失效,
他只是會把數(shù)組的長度標記為新長度,后面空閑出來那一段內(nèi)存不會釋放掉
繼續(xù)留在那里,直到vector對象被析構(gòu)。
調(diào)用了a.resize(2);之后,數(shù)組的容量仍然是5,
因此重新擴容到5是不需要重新分配內(nèi)存的,也就不會移動元素導致指針失效。

vector容器: capacity函數(shù)查詢實際的最大容量

szie_t capacity() const noexcept();
	int main()
	{
		vector<int>a={1,2,3,4,5};
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reszie(2); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reszie(5); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reszie(7); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;

		a.reszie(12); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;

		return  0; 
	}
可以用capacity()函數(shù)查詢已經(jīng)分配內(nèi)存的大小,即最大容量。
而szie()返回的其實是已經(jīng)存儲了數(shù)據(jù)的數(shù)組長度。
可以發(fā)現(xiàn)當resize指定的新長度一個超過原來的最大容量時,就會重新分配一段更大容量的內(nèi)存來存儲數(shù)組,只有這時才會移動元素的位置(data指針失效)。

注意這里resiez(7)之后容量實際上擴充到了10而不是剛好為7,為什么呢?
因為標準庫的設計者為了減少重復分配的次數(shù),他有一個策略:當resize后的新尺寸變化較小時,則自動寬容到原尺寸的兩倍。
這里我們的原大小是5,所以resize(7)會擴充容量到10,但是尺寸為7.

尺寸總是小于等于容量 尺寸范圍內(nèi)都是已初始化的內(nèi)存(0) 尺寸到容量之間的范圍是未初始化的。

如果resize后的尺寸還超過了原先尺寸的兩倍就沒有這個效果了
實際上resize(n)的邏輯是擴容到max(n,capacity*2);

vector容器:reserve預留一定容量,避免之后重復分配 只會擴容不會減容

size_t reserve(szie_t n);
	int main()
	{
		vector<int>a={1,2,3,4,5};
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reserve(12); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reszie(2); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;
		a.reszie(5); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;

		a.reszie(12); 
		cout<<a.data()<<' ' <<a.szie();<<'/'<<a.capacity()<<endl;

		return  0; 
	}
內(nèi)存分配是需要一定時間的,可以用reserve函數(shù)預留一定的容量
這樣之后就不會出現(xiàn)容量不足而需要動態(tài)擴容影響性能了
如這里一開始預留了12格容量,從5到12的時候就不必重新分配,reserve時也會移動元素

vector讀取寫入

vector 容器:operator[] 	要訪問vector里的元素,只需要[]運算符;
			int& operator[](size_t n)
			int const &operator[](size_t n)
vector<int>a(4);		
cout<<"a[0] = " <<a[0]<<endl;
例如 a[0]訪問第0個元素(人類的第一個)

cout<<"a[1000] = " <<a[1000]<<endl;		 越界訪問并不會直接保存	 會導致異常

為了防止不小心越界 可以用 a.at(i) 代替 a[i] 		at函數(shù)會檢測索引i是否越界 如果索引i>=a.szie()則會拋出異常 std::out_of_range

operator[]和at 除了讀取還可以寫入	因為他們返回的是元素的引用int&  
例如:給第i個元素賦值val	a[i] =val	cout<<a[i]<<endl;

vector容器:構(gòu)造函數(shù)

vector這個顯式構(gòu)造函數(shù),默認會把所有元素初始化為0(不必手動去memset)

如果是自定義類,則會調(diào)用元素的默認構(gòu)造函數(shù)(例如:數(shù)字類型初始化為0 ,string會初始化為空字符串,指針類型會初始化為nullptr)

重載cout輸出流格式

重載cout輸出流格式

main.cpp
#include "printer.h"
using namespace std;

int main()
{
vector&lt;
int&gt;a(4);
cout <<a << endl;
return 0;
}
printer.h
#pragma once
#include<iostream>
#include<vector>
/*在c++標準庫命名空間std中,為 vector<t> 類型定義了一個輸出流運算符重載函數(shù),重載了 << 操作符
重載函數(shù)的功能是將vector對象的元素輸出到一個輸出流 其中 os 表示輸出流 v 表示要輸出的vector對象
函數(shù)體中使用迭代器遍歷 vector 對象并將每個元素序列化為字符流,并將其連接成一個逗號分隔的字符串形式
*/
namespace std {
	template <class T>
	ostream& operator<<(ostream& os, vector<T> const& v)
	{
		os << '{';
		auto  it = v.begin();
		if (it!=v.end())
		{
			os << *it;
			for (++it; it != v.end(); ++it)
			{
				os << ',' << *it;
			}
		}
		os << '}';
		return os;
	}
}

vector 迭代器模式

將這個打印的操作封裝起來怎么做?

int main(){
		vector<char> a ={'h','j','k','l'};
		for(int i =0;i<a.size();i++){
			cout<<a[i]<<endl;		
		}
		return 0;
	}
可以用一個函數(shù)來封裝打印操作:void Print(vector<char> const &a)
	void Print(vector<char> const &a){		//a不用被改寫所以加了const引用 改寫的話非const的即可
		 for(int i =0;i<a.size();i++){
			cout<<a[i]<<endl;
		}
	}	
	
	int main(){
		vector<char> a ={'h','j','k','l'};
	 	Print(a);
		return 0;
	}

將這個打印的操作封裝起來怎么做?

void Print(vector<char> const &a) //只能打印vector類型,沒有打印string類型
//要支持只能再寫一遍一樣的print函數(shù)
	void Print(vector<char> const &a){		 
		 for(int i =0;i<a.size();i++){
			cout<<a[i]<<endl;
		}
	}	
	
	int main(){
		vector<char> a ={'h','j','k','l'};
	 	Print(a);
		string b = {'h','j','k','l'};
		print(b);
		return 0;
	}	
string 和vector 都是連續(xù)的數(shù)組 內(nèi)存都是連續(xù)的 他們都有data()和size()函數(shù)	
所以可以把他們的初始地址和長度獲取出來改用首地址指針和數(shù)組長度做參數(shù)
void print(char const *a,size_t n){		
/*a不是數(shù)組對象 而是首地址指針 指針也可以訪問數(shù)組,這樣就可以不用知道它是什么類型只需要知道它是連續(xù)的就*/
		for(int i =0;i<n;i++)
			cout<<a[i]<<endl;
	}
 	int main(){
		vector<char> a ={'h','j','k','l'};
	 	Print(a.data(),a.size());
		string b = {'h','j','k','l'};
		print(b.data(),b.szie());
		return 0;
	}	
使用指針和長度做接口的好處可以通過指針加減運算,選擇其中一部分連續(xù)的元素來打印,
而不一定全部打印出來。

比如說我們選擇打印前三個元素去點最后一個元素,但不必用pop_back修改數(shù)組,只要傳參數(shù)的時候修改一下長度即可
void print(char const *a,size_t n){		 
	for(int i =0;i<n;i++)
		cout<<a[i]<<endl;
}
int main(){
	vector<char> a ={'h','j','k','l'};
 	Print(a.data()+1,a.size()-1);	//打印了jkl
	return 0;
}	
//可以添加stride為步長
		void print(char const *a,size_t n,i nt stride){		 
		for(int i =0;i<n;i++)
			cout<<a[i]*stride<<endl;
		}
 		int main(){
			vector<char> a ={'h','j','k','l'};
		 	Print(a.data(),a.size()-1,1);
			return 0;
		}	

為什么尾指針要往后移動一格?

讓尾地址指針往后移動一格的設計,使得數(shù)組長度為0就是begptr==endptr的清空
非常容易判斷,同時可以通過endptr-begptr算出數(shù)組的長度
//首尾對稱指針
		void print(char const *begptr ,char const *endptr){
			for(char const*ptr =begptr;ptr!=endptr;ptr++)
				{	
					char value =*ptr;
					cout<<value<<endl;
				}
		}
		
		int main(){
			vector<char> a ={'h','j','k','l'};
			char const *begptr = a.data();
			char const *endle = a.data()+a.size(); //尾指針指向的是不可訪問的,是多一個的 尾指針-頭指針=size()實際數(shù)組大小
			size_t size =endptr-begptr;
			cout<<"begptr-endptr = "<<size<<endl;
			print(begptr,endptr);
			return 0;
		}

模板函數(shù)

可以讓首指針和尾指針聲明為模板參數(shù)這樣不論指針是什么類型
都可以使用print這個模板函數(shù)來打印
		template<class Ptr>
	void print(Ptr begptr,Ptr endptr){
		for(Ptr ptr =begptr;ptr!=endptr;ptr++)
			{	
				auto value =*ptr;
				cout<<value<<endl;
			}
	}

	int main(){
		vector<char> a ={'h','j','k','l'};
		char const *begptr = a.data();
		char const *endle = a.data()+a.size();  
		print(begptr,endptr);
		vector<int> b ={1,2,3,5};
		int const *begptr = a.data();
		int const *endle = a.data()+a.size();  
		print(begptr,endptr);
		return 0;
	}

C++運算符重載,它可以讓你的返回值不是一個指針而是一個特殊的類(迭代器) ++運算符的內(nèi)部其實不是給指針++反而是把它的結(jié)點指針指向結(jié)點的next
list的iterator類 重載了++運算符實際上是對應鏈表的curr=curr->next文章來源地址http://www.zghlxwxcb.cn/news/detail-422697.html

	template<class Ptr>
	void print(Ptr begptr,Ptr endptr){
		for(Ptr ptr =begptr;ptr!=endptr;ptr++)		//!=是否到達位置 ++代表往后走一格 *結(jié)點引用
			{	
				auto value =*ptr;
				cout<<value<<endl;
			}
	}
	list提供了begin()和end()函數(shù) 他們會返回兩個list<char>::iteratr對象
	list<char>::iterator是一個特殊定義過的類型,其具有!=和++以及*這些運算符的重載,所以用起來就像普通的指針一樣。而這些運算符的重載,卻會把++對應到鏈表的curr= curr->next上。
	這樣一個用起來就像普通的指針,但內(nèi)部卻通過運算符重載適配不同容器的特殊類就是迭代器(iterator),迭代器是STL容器和算法之間的橋梁。
	int main(){
		list<char> a ={'h','j','k','l'};
		list<char>::iterator begptr = a.begin();
		list<char>::iterator endptr= a.end();
		print(begptr,endptr);
		return 0;
	}

迭代器的精髓:把連續(xù)的訪問映射到鏈表的不連續(xù)訪問上 首迭代器+尾迭代器

template<class T>
struct list{
		struct Node{
			T value; 
			Node *next;
	};		
		struct Interator{
			Node *curr;

			Iterator &operator++(){  //++p
			curr =curr->next;
			return *this;
		}	
			Iterator operator++(int){	//p++
			Iterator tmp =*this;
			this->operator++();
			return tmp;
		}


		T &operator*() const{
			return curr->value;
		}

		bool operator!=(Iterator const *that)const{
			return curr!=that.curr;
		}
	};
	Node *head;
	Iterator begin(){ return {head}; }
	Iterator end(){ return {nullptr}; }
}

迭代器模式:++的前置和后置

	++p與p++都會產(chǎn)生p=p+1的效果,區(qū)別在于他們被作為表達式時的返回值。
	++p會返回自增后的值p+1這和p+=1完全一樣,同樣因為返回的是一個左值引用所還可以繼續(xù)自增比如+++++p
	p++會返回自增前的值p,但是執(zhí)行完以后p又是p+1了
	正因為如此,后置自增需要先保存舊的迭代器,然后自增自己,在返回舊迭代器可能會比較低效。
Iterator operator++(int){	//p++
			Iterator tmp =*this;
			this->operator++();
			return tmp;
		}
	例如: p=1; int x =++p; 	x=2 p=2;
		   p=1  int x =p++;  	x=1 p=2;

vector容器:begin end 區(qū)間可以方便切片

begin可以獲取指向第一個元素所在位置的迭代器
end可以獲取指向最后一個元素下一個位置的迭代器	迭代器的作用類似于一個位置標記符
C++的特色就是采用了迭代器(iterator)來標記位置,他實際上時一個指針,
這樣的好處是:不需要指定1原來的容器本身,就能知道指定的位置。
一隊迭代器begin和end就表及了一個區(qū)間range,區(qū)間可以是一個容器的全部
	例如:{a.begin()+1,a.end()-1}相當于去頭去尾后的列表相當于python中的a[1:-1 ]
int main(){
	vector<int> a ={1,2,3,4,5,6};
	vector<int>::iterator b  = a.begin();
	vector<int>::iterator e = a.end(); 

	cout<<"a="<<a<<endl;
	cout<<"*b="<<*b<<endl;
	cout<<"*(b+1)="<<*(b+1)<<endl;
	cout<<"*(b+2)="<<*(b+2)<<endl;
	cout<<"*(e-2)="<<*(e-2)<<endl;
	cout<<"*(e-1)="<<*(e-1)<<endl;
	cout<<"*e="<<*e<<endl;

	return 0;
}
begin可以獲取第一個元素所在位置的迭代器,可以提供*a.begin()來訪問第一個元素
迭代器支持加法運算,例如*(a.begin()+1)就是訪問數(shù)組的第二個元素了,和a[1]等價
end可以獲取指向最后一個元素下一個位置的迭代器,也就是說end指向的位置是不可用的!
如需訪問最后一個元素必須用*(a.end()-1)才行。
int main(){
	vector<int> a ={1,2,3,4,5,6};
	vector<int>::iterator b  = a.begin();
	vector<int>::iterator e = a.end(); 

	cout<<"a="<<a<<endl;
	cout<<"b[0]"<<b[0]<<endl;
	cout<<"b[1]="<<b[1]<<endl;
	cout<<"b[2]="<<b[2]<<endl;
	cout<<"e[-2]="<<e[-2]<<endl;
	cout<<"e[-1]="<<e[-1]<<endl;
	cout<<"e[0]="<<e[0]<<endl;

	return 0;
}
迭代器實際上可以用[]運算符訪問,例如 b[i] =*(b+i)等價
不過只有vector這種連續(xù)的可隨機訪問容器的迭代器有+和[]運算符,對于list則只有*和++,--運算符可以用
	
迭代器和容器本身的主要區(qū)別在于:迭代器不掌握生命周期,從而迭代器的拷貝是平凡的淺拷貝,方便傳參。
	 淺拷貝:拷貝數(shù)據(jù)	深拷貝:復制地址
	同時的缺點,因為迭代器是一個原容器的弱引用,如原容器解構(gòu)或者發(fā)生內(nèi)存重新分配,迭代器就會失效。






到了這里,關(guān)于STL標準模板庫 vector容器與迭代器入門的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關(guān)文章

  • c++ 11標準模板(STL) std::vector (二)

    c++ 11標準模板(STL) std::vector (二)

    template ? ? class T, ? ? class Allocator = std::allocatorT class vector; (1) namespace pmr { ? ? template class T ? ? using vector = std::vectorT, std::pmr::polymorphic_allocatorT; } (2) (C++17 起) 1) std::vector 是封裝動態(tài)數(shù)組的順序容器。 2) std::pmr::vector 是使用多態(tài)分配器的模板別名。 元素相繼存儲,這意味著不

    2024年02月02日
    瀏覽(17)
  • 【C++庖丁解?!縎TL之vector容器的介紹及使用 | vector迭代器的使用 | vector空間增長問題

    【C++庖丁解?!縎TL之vector容器的介紹及使用 | vector迭代器的使用 | vector空間增長問題

    ??你好,我是 RO-BERRY ?? 致力于C、C++、數(shù)據(jù)結(jié)構(gòu)、TCP/IP、數(shù)據(jù)庫等等一系列知識 ??感謝你的陪伴與支持 ,故事既有了開頭,就要畫上一個完美的句號,讓我們一起加油 vector的文檔介紹 vector是表示可變大小數(shù)組的序列容器。 就像數(shù)組一樣,vector也采用的連續(xù)存儲空間來存

    2024年03月14日
    瀏覽(36)
  • C++、STL標準模板庫和泛型編程 ——迭代器、 算法、仿函數(shù)(侯捷)

    C++、STL標準模板庫和泛型編程 ——迭代器、 算法、仿函數(shù)(侯捷)

    侯捷 C++八部曲筆記匯總 - - - 持續(xù)更新 ! ! ! 一、C++ 面向?qū)ο蟾呒夐_發(fā) 1、C++面向?qū)ο蟾呒壘幊?上) 2、C++面向?qū)ο蟾呒壘幊?下) 二、STL 標準庫和泛型編程 1、分配器、序列式容器 2、關(guān)聯(lián)式容器 3、迭代器、 算法、仿函數(shù) 4、適配器、補充 三、C++ 設計模式 四、C++ 新標準 五、

    2023年04月25日
    瀏覽(34)
  • 15 標準模板庫STL之容器1

    基礎知識 ????????1、vector和數(shù)組有點類似,但它比數(shù)組更好用。一般來說,數(shù)組的長度是不能動態(tài)拓展的,因此就需要考慮長度到底多大合適。長度不能過大,否則浪費內(nèi)存;也不能過小,否則內(nèi)存不夠。vector正好彌補了這個缺陷,相當于一個可以自動改變數(shù)組長度的動

    2023年04月12日
    瀏覽(21)
  • C++——STL標準模板庫——容器詳解——list

    C++——STL標準模板庫——容器詳解——list

    list:雙向鏈表。list是一種分布式存儲的線性表,每個節(jié)點分為數(shù)據(jù)域和指針域,其中指針域中包含一個指向前驅(qū)節(jié)點的指針和一個指向后續(xù)節(jié)點的指針,基本模型如下: 1、雙向鏈表:每個元素都有一個前驅(qū)和一個后繼,這種結(jié)構(gòu)允許在鏈表的任何位置實現(xiàn)快速的插入和刪除

    2024年01月16日
    瀏覽(22)
  • 22 標準模板庫STL之容器適配器

    概述 ????????提到適配器,我們的第一印象是想到設計模式中的適配器模式:將一個類的接口轉(zhuǎn)化為另一個類的接口,使原本不兼容而不能合作的兩個類,可以一起工作。STL中的容器適配器與此類似,是一個封裝了序列容器的類模板,它在一般序列容器的基礎上提供了一

    2024年02月05日
    瀏覽(23)
  • C++day7(異常處理機制、Lambda表達式、類型轉(zhuǎn)換、STL標準庫模板、迭代器、list)
  • 【C++入門】STL容器--vector底層數(shù)據(jù)結(jié)構(gòu)剖析

    【C++入門】STL容器--vector底層數(shù)據(jù)結(jié)構(gòu)剖析

    目錄 ?前言 ?1. vector的使用 ? ? ??vector的構(gòu)造 ?vector迭代器 ?vector空間相關(guān)的接口 ?vector 功能型接口 ?find ?swap ?insert ?erase 2. vector內(nèi)部數(shù)據(jù)結(jié)構(gòu)剖析 reserve ?push_back和pop_back size、capacity、empty、operator[ ]; ?insert和erase resize swap ?拷貝構(gòu)造和賦值重載 構(gòu)造函數(shù)補充 ?迭代器

    2024年01月25日
    瀏覽(22)
  • C++ STL 標準模板庫介紹與入門

    目錄 1、概述 1.1、C++ 標準庫 1.2、Boost庫 2、STL 版本 2.1、HP 原始版本

    2024年02月05日
    瀏覽(27)
  • STL常用梳理——VECTOR常用接口及其迭代器實現(xiàn)

    STL常用梳理——VECTOR常用接口及其迭代器實現(xiàn)

    vector是STL中容器之一,特性如下: vector是表示可變大小數(shù)組的序列容器。 就像數(shù)組一樣,vector也采用的連續(xù)存儲空間來存儲元素。也就是意味著可以采用下標對vector的元素 進行訪問,和數(shù)組一樣高效。但是又不像數(shù)組,它的大小是可以動態(tài)改變的,而且它的大小會被容器自

    2024年02月05日
    瀏覽(30)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包