做3d模型的叫什么牛的網(wǎng)站色盲眼中的世界
目錄
引言
vector容器的基本概念
1.功能
2.動態(tài)大小
3.動態(tài)擴(kuò)展
vector的接口
1.vector的迭代器
2.vector的初始化與銷毀
3.vector的容量操作
3.1 有效長度和容量大小
(1)使用示例
(2)擴(kuò)容機(jī)制
3.2 有效長度和容量操作
(1)reserve
(2)resize
4.vector的訪問操作
5.vector的修改操作
迭代器失效
結(jié)束語
引言
在我的博客?C++——string的了解和使用?中,我們學(xué)習(xí)了標(biāo)準(zhǔn)模板庫(STL)中的string的一些基礎(chǔ)內(nèi)容,今天我們來學(xué)習(xí) vector 。
vector容器的基本概念
在C++中,vector 是一個非常重要的容器,它屬于標(biāo)準(zhǔn)模板庫的一部分。vector 提供了一種動態(tài)數(shù)組的實(shí)現(xiàn),可以在運(yùn)行時(shí)動態(tài)地增加或減少其大小,同時(shí)保持元素的連續(xù)存儲。
1.功能
vector是可變大小的序列容器,采用連續(xù)存儲空間存儲元素,可通過下標(biāo)高效訪問。
2.動態(tài)大小
與靜態(tài)數(shù)組不同,vector 的大小可以在運(yùn)行時(shí)動態(tài)地改變。此外,靜態(tài)數(shù)組內(nèi)數(shù)據(jù)通常存儲在棧上,而vector中數(shù)據(jù)存儲在堆上。
3.動態(tài)擴(kuò)展
動態(tài)擴(kuò)展的核心在于,當(dāng)現(xiàn)有內(nèi)存空間不足以滿足需求時(shí),不是簡單地在原空間后續(xù)接新空間(這在連續(xù)內(nèi)存分配中通常是不現(xiàn)實(shí)的,因?yàn)楹罄m(xù)空間可能已被其他程序或數(shù)據(jù)占用),而是采取以下步驟:
(1)分配新空間:找到一個足夠大的、連續(xù)的新內(nèi)存空間。這個新空間的大小要能夠容納原數(shù)據(jù)和新數(shù)據(jù)。
(2)數(shù)據(jù)拷貝:將原內(nèi)存空間中的數(shù)據(jù)復(fù)制到新分配的內(nèi)存空間中。這個過程中需要確保數(shù)據(jù)的完整性和正確性。
(3)釋放原空間:在數(shù)據(jù)成功拷貝到新空間后,釋放原來的內(nèi)存空間。這一步是為了避免內(nèi)存泄漏。
(4)更新指針:將指向原內(nèi)存空間的指針更新為指向新內(nèi)存空間的指針。這樣,程序就可以繼續(xù)在新空間中操作數(shù)據(jù)。
此外,使用vector時(shí)必須包含頭文件 #include<vector> 。
vector的接口
我們使用如下文檔來輔助我們學(xué)習(xí)vector:
vector的接口詳細(xì)介紹
1.vector的迭代器
與string一樣,vector中也有迭代器。由于vector定義在vector類中,因此我們想要使用vector的迭代器需要通過域作用限定符訪問——vector<類型>::iterator 。
其中,begin(),end(),rbeign(),rend()的使用訪問方法與string中的類似,
我們來看看代碼演示:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };vector<int>::iterator it = vec.begin();cout << "順序遍歷:";while (it != vec.end()){cout << *it << " ";it++;}cout << endl;cout << "逆序遍歷:";vector<int>::reverse_iterator rit = vec.rbegin();while (rit != vec.rend()){cout << *rit << " ";++rit;}return 0;
}
輸出結(jié)果如下:
同樣的,vector也支持const_iterator:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;return 0;
}
2.vector的初始化與銷毀
vector 類的賦值運(yùn)算符 operator= 被重載以支持將一個 vector 的內(nèi)容復(fù)制到另一個 vector 中。
vector 支持多種構(gòu)造函數(shù),拷貝構(gòu)造以及賦值運(yùn)算符重載。
下面是一些簡單的使用:
void printVector(vector<int>& vec)
{ for (vector<int>::iterator it = vec.begin(); it != vec.end(); ++it){cout << *it << " ";}cout << endl;
}int main()
{vector<int> vec1; for (int i = 0; i < 5; ++i){vec1.push_back(i);}vector<int> vec2(vec1.begin(), vec1.end()); vector<int> vec3(5, 5); vector<int> vec4(vec3); cout << "打印vec2: ";printVector(vec2);cout << "打印vec3: ";printVector(vec3);cout << "打印vec4: ";printVector(vec4);return 0;
}
輸出結(jié)果為:
int main()
{vector<int> vec1, vec2;for (int i = 0; i < 5; i++){vec1.push_back(i);}vec2 = vec1;printVector(vec2);return 0;
}
輸出結(jié)果為:
3.vector的容量操作
如下表格是關(guān)于vector的一些基礎(chǔ)的容量操作:
函數(shù)名稱 | 功能 |
size | 返回vector的有效長度 |
capacity | 返回vector的容量大小 |
clear | 清空vector |
empty | 檢查vector是否為空,是則返回ture,否則返回false |
reserve | 請求改變vector的容量 |
resize | 重新設(shè)置有效元素的數(shù)量,超過原來有效長度則用c字符填充 |
3.1 有效長度和容量大小
(1)使用示例
與 string類 類似,我們可以使用 size()返回容器的有效長度;capacity()返回容器的容量大小。
下面是簡單的測試用例:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };cout << vec.size() << endl;cout << vec.capacity() << endl;if (vec.empty()){cout << "vec為空" << endl;}else{cout << "vec不為空" << endl;}vec.clear();if (vec.empty()){cout << "vec為空" << endl;}else{cout << "vec不為空" << endl;}return 0;
}
輸出結(jié)果為:
通常來說,vector的有效長度和容量大小相同
(2)擴(kuò)容機(jī)制
接下來我們來看看vector的擴(kuò)容機(jī)制:
int main()
{size_t sz;vector<int> vec;sz = vec.capacity();cout << "making vec grow:" << endl;for (int i = 0; i < 100; ++i){vec.push_back(i);if (sz != vec.capacity()){sz = vec.capacity();cout << "capacity changed: " << sz << endl;}}
}
輸出結(jié)果為:
在vs2022中,vector是以1.5倍進(jìn)行擴(kuò)容處理的,
我們現(xiàn)在把這段代碼放到g++中運(yùn)行看看:
我們可以看到,在此環(huán)境中,vector是以二倍進(jìn)行擴(kuò)容的。
3.2 有效長度和容量操作
接下來我們來學(xué)習(xí)vector中的reserve和resize(這倆函數(shù)的使用與string中的差不多)。
(1)reserve
reserve 函數(shù)用于請求改變?nèi)萜鞯娜萘?#xff0c;即分配足夠的內(nèi)存空間以容納至少指定數(shù)量的元素
簡單使用一下:
int main()
{vector<int> vec;vec.reserve(10);cout << vec.capacity() << endl;return 0;
}
輸出結(jié)果為:
(2)resize
resize的使用有如下兩種:
resize(int num);
如果 num 小于當(dāng)前容器的大小,那么容器末尾的多余元素將被刪除。如果 num 大于當(dāng)前容器的大小,則容器將被擴(kuò)展,新添加的元素將被初始化為該類型的默認(rèn)值(對于內(nèi)置類型如 int,默認(rèn)值為 0)。
resize(int num, int elem);
這個方法同樣用于將 std::vector 的大小調(diào)整為 num,但在容器需要擴(kuò)展時(shí),新添加的元素將被初始化為 elem 而不是默認(rèn)值。如果 num 小于當(dāng)前容器的大小,多余元素的處理方式與第一個 resize 方法相同,即被刪除。
簡單的使用一下:
int main()
{vector<int> vec = { 1,2,3,4,5 };vec.resize(3);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;vec.resize(4);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;vec.resize(5, 9);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;return 0;
}
輸出結(jié)果為:
4.vector的訪問操作
vector的訪問操作有如下幾個:
函數(shù)名稱 | 功能 |
operator[] | 返回指定位置的元素,越界則報(bào)錯 |
at | 返回指定位置的元素,越界則拋異常 |
front | 返回字符串第一個元素 |
back | 返回字符串最后一個元素 |
這些函數(shù)的用法也與string中的函數(shù)用法差不多,就不多介紹了,來看看代碼:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;for (int i = 0; i < vec.size(); i++){cout << vec.at(i) << " ";}cout << endl;cout << "front:" << vec.front() << endl;cout << "back:" << vec.back() << endl;return 0;
}
輸出結(jié)果為:
5.vector的修改操作
vector的修改操作有如下幾個:
函數(shù)名稱 | 功能 |
push_back | 在數(shù)組后追加元素 |
pop_back | 刪除數(shù)組最后一個元素 |
insert | 在指定位置追加元素 |
assign | 使用指定數(shù)組替換原數(shù)組 |
erase | 刪除數(shù)組指定部分區(qū)間 |
swap | 交換兩個數(shù)組 |
先來看看push_back(),pop_back(),assign(),swap() :
int main()
{vector<int> vec1 = { 0,1,2,3,4,5,6,7,8,9 };cout << "back:" << vec1.back() << endl;// 元素尾插vec1.push_back(10);// 元素尾刪cout << "back:" << vec1.back() << endl;vec1.pop_back();cout << "back:" << vec1.back() << endl;vector<int> vec2 = { 9,9,9,9,9 };vec2.assign(3, 3);for (int i = 0; i < vec2.size(); i++){cout << vec2[i] << " ";}cout << endl;vec2.swap(vec1);for (int i = 0; i < vec1.size(); i++){cout << vec1[i] << " ";}cout << endl;for (int i = 0; i < vec2.size(); i++){cout << vec2[i] << " ";}cout << endl;return 0;
}
輸出結(jié)果如下:
我們再來看看insert和erase:
insert函數(shù):
來看代碼:
int main()
{vector<int> vec1(5, 10);vector<int>::iterator it = vec1.begin();it = vec1.insert(it, 100);cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;vec1.insert(it, 2, 1000);it = vec1.begin();cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;vector<int> vec2(2, 10000);it = vec1.begin();vec1.insert(it + 2, vec2.begin(), vec2.end());cout << "vec1:";for (it = vec1.begin(); it < vec1.end(); it++){cout << *it << " ";}cout << endl;return 0;
}
輸出結(jié)果為:
erase函數(shù):
簡單的代碼演示如下:
int main()
{vector<int> vec = { 0,1,2,3,4,5,6,7,8,9 };vector<int>::iterator it = vec.erase(vec.begin() + 3); // 刪除值為3的元素it = vec.erase(it); // 刪除值為4的元素for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;it = vec.erase(vec.begin(), vec.begin() + 5);for (int i = 0; i < vec.size(); i++){cout << vec[i] << " ";}cout << endl;return 0;
}
輸出結(jié)果為:
迭代器失效
迭代器的主要作用就是讓算法能夠不用關(guān)心底層數(shù)據(jù)結(jié)構(gòu),其底層實(shí)際就是一個指針,或者是對 指針進(jìn)行了封裝,比如:vector的迭代器就是原生態(tài)指針T* 。因此迭代器失效,實(shí)際就是迭代器 底層對應(yīng)指針?biāo)赶虻目臻g被銷毀了,而使用一塊已經(jīng)被釋放的空間,造成的后果是程序崩潰(即 如果繼續(xù)使用已經(jīng)失效的迭代器,程序可能會崩潰)。
以下可能會導(dǎo)致迭代器失效:
1.會引起其底層空間改變的操作,都有可能使迭代器失效
int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// 將有效元素個數(shù)增加到100個,多出的位置使用8填充,操作期間底層會擴(kuò)容// v.resize(100, 8);// reserve的作用就是改變擴(kuò)容大小但不改變有效元素個數(shù),操作期間可能會引起底層容量改變// v.reserve(100);// 插入元素期間,可能會引起擴(kuò)容,而導(dǎo)致原空間被釋放// v.insert(v.begin(), 0);// v.push_back(8);// 給vector重新賦值,可能會引起底層容量改變//v.assign(100, 8);/*出錯原因:以上操作,都有可能會導(dǎo)致vector擴(kuò)容,也就是說vector底層原理舊空間被釋放掉,而在打印時(shí),it還使用的是釋放之間的舊空間,在對it迭代器操作時(shí),實(shí)際操作的是一塊已經(jīng)被釋放的空間,而引起代碼運(yùn)行時(shí)崩潰。解決方式:在以上操作完成之后,如果想要繼續(xù)通過迭代器操作vector中的元素,只需給it重新賦值即可。 */while (it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
2.指定位置元素的刪除操作--erase
int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 刪除pos位置的數(shù)據(jù),導(dǎo)致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此處會導(dǎo)致非法訪問return 0;
}
3.與vector一樣,string在插入+擴(kuò)容操作+erase之后,迭代器也會失效
int main()
{string s("hello");auto it = s.begin();// 放開之后代碼會崩潰,因?yàn)閞esize到20會string會進(jìn)行擴(kuò)容// 擴(kuò)容之后,it指向之前舊空間已經(jīng)被釋放了,該迭代器就失效了// 后序打印時(shí),再訪問it指向的空間程序就會崩潰//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式寫,運(yùn)行時(shí)程序會崩潰,因?yàn)閑rase(it)之后// it位置的迭代器就失效了// s.erase(it); ?++it;}return 0;
}
結(jié)束語
寫完啦~\(≧▽≦)/~
接下來會愈加忙碌,希望自己還能擠出時(shí)間寫博客=_=
感謝各位大佬的支持!!!
求點(diǎn)贊收藏評論關(guān)注!!!