文章目錄
- vector介紹
- vector和string的區別
- 補充知識
- initializer_list
- emplace_back
- 結構化綁定
- vector的使用
- 構造
- 析構
- 遍歷+修改
- insert
- find
- 流插入/流提取
- vector\<vector>(楊輝三角)
- vector模擬實現
- 淺品STL源碼
- 構造函數
- 拷貝構造
- 多參數構造
- 迭代器區間構造
- n個val初始化
- swap
- operator=
- reserve
- size
- capacity
- push_back(補充解釋源碼里為什么要用定位new)
- 迭代器
- pop_back
- insert(補充迭代器失效)
- erase
- clear
- resize
- 深層次的深拷貝問題
- 源碼
vector介紹
vector底層和string一樣也是數組,類似數據結構我們介紹的順序表。
它和string的區別是string的元素類型只能是字符類型,vector有模板可以是任何類型,包括自定義類型。
vector和string的區別
既然vector和string底層都是數組,那存char類型數據的vector<char>和string有什么區別呢?
1、雖然vector也有date接口返回底層數組首元素的指針,但是vector<char>末尾沒有\0,無法兼容c語言。
2、vector插入數據只有push_back插入一個數據,find也只能找一個數據,但是string有字符串的概念,所以它有append,operator+=插入字符串,find也能找子串。
補充知識
initializer_list
- 這是C++11引入的新語法,initializer_list是一種類型,使用它需要包<initializer_list>頭文件。
- 我們把一些數據用大括號括起來一起賦值給i1,這個i1類型就是initializer_list。
它是底層在棧上開了一塊空間,把常量數組存起來,有一個指針指向開始,有一個指針指向結束,所以它支持迭代器,有size()和范圍for,后面講vector多參數構造的底層實現會用到。
用法:
- typid()可以打印一個對象或者類型的真實類型。
- initializer_list支持迭代器,所以可以用迭代器遍歷。
用途:
- C++11要引入這個新語法是一是為了支持用任意多個值直接構造初始化容器,操作如下:
vector<int> v1({ 10, 20, 30 });vector<double> v2({ 10.1, 20.4, 30.7, 40.6, 50.5 });
這就是直接調用構造函數。
但是我們實際更喜歡用下面這種操作:
vector<int> v1 = { 10, 20, 30 };vector<double> v2 = { 10.1, 20.4, 30.7, 40.6, 50.5 };
這里會隱式類型轉換,initializer_list會先構造一個vector,再拷貝構造給給對象,編譯器會優化為直接構造。
- 二是可以用于多參數構造函數的隱式類型轉換:
struct A{A(int a1, int a2):_a1(a1),_a2(a2){}int _a1;int _a2;};vector<A> v1;A aa1(1, 1);//有名對象v1.push_back(aa1);//匿名對象v1.push_back(A(2, 3));//多參數隱式類型轉換v1.push_back({4,5});
emplace_back
這里小編只能介紹它的用法,理解他還需要后面的知識。
它是模板的可變參數,在上面多參數隱式類型轉換的時候像下面這樣用,效率會更高。
A1.emplace_back(4,5);
結構化綁定
auto [x, y] = aa1;for (auto [X, Y] : v1){cout << X << ':' << Y << endl;}
當對象是一個結構對象比如結構體體時,可以用上面這種方法訪問對象的成員。
vector的使用
這里小編不會一一介紹,和string基本一樣的接口就跳過了,和string有區別的會挑出來介紹。
構造
//默認構造vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);//10個1構造vector<int> v2(10, 1);//迭代器區間構造vector<int> v3(v2.begin(), v2.end())
析構
~vector(){if (_first){delete[] _first;_first = _finish = _endofstorage = nullptr;}}
_first不為空再delete,delete后記得把指針置空。
遍歷+修改
//使用size()for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//范圍forfor (auto e : v2){cout << e << " ";}cout << endl;//迭代器vector<int>::iterator it = v3.begin();while (it != v3.end()){cout << (*it) << " ";it++;}cout << endl;
insert
vector的插入重載要比string少很多,并且vector是以迭代器為標準插入的,string是size_t pos為標準。
//頭插v1.insert(v1.begin(), 1000);//下標為3的位置前面插入v1.insert(v1.begin() + 3, 1000);
find
- vector并沒有自己的find,它用的是算法庫的find,它是在一段迭代器區間查找。
- string要自己實現find是因為string需要從某一位置開始向后查找還要查找子串。
算法庫的find是通過一段迭代器區間找,因為迭代器區間是左閉右開的,所以找到了就返回第一個找到的元素的迭代器,沒找到就返回last。
auto it = find(v1.begin(), v1.end(), 10);if (it != v1.end()){v1.insert(it, 100);}
流插入/流提取
- vector以及后面的容器都不再提過輸入輸出,要輸入輸出自己通過范圍for或者迭代器實現。
- string提供因為會經常輸入輸出字符串。
vector<vector>(楊輝三角)
在介紹vector<vector>之前我們先看一道題:
題目鏈接:楊輝三角
這道題就需要用到vector<vector>來實現C語言類似二維數組的功能。
要理解vector我們先理解它是如何實例化的,我們以vector<vector<int>>為例:
這里和C語言單純的二維數組不同,vector<vector>是對象數組。
當我們要讀寫vector<vector<int>>需要采用和C語言一樣的方法,但是底層原理已經完全不同了,C語言的指針的偏移和解引用,這里是兩個函數的調用,下面代碼兩種寫法是等價的,第一個是vector<vector>里的operator[],返回值的vector<int>&,返回值是可以修改的,第二個是vector<int>里的operator[],返回值是int&。有些讀者可能會有疑問,兩個函數調用不會拉低效率嗎?內聯函數的作用就體現出來了,operator[]很短小,所以會直接內聯展開替換成指令,不會調用函數。
vv[i][j];
vv.operator[](i).operator[](j);
完整代碼:
class Solution {
public:vector<vector<int>> generate(int numRows) {//定義vector<vector>+開空間vector<vector<int>> vv;//開numRows行個空間,resize第二個參數要傳對象,這里是匿名對象vv.resize(numRows, vector<int>());for(int i = 0; i < numRows; i++){//每一列數據個數是列數加1vv[i].resize(i + 1, 1);}//控制行//前兩行不用動,i從2開始for(int i = 2; i < vv.size(); i++){//控制列//每列的第一個和最后一個不用動for(int j = 1; j < vv[i].size() - 1; j++){vv[i][j] = vv[i - 1][j - 1] + vv[i - 1][j];}}return vv;}
};
vector模擬實現
首先我們要明確這里我們只用兩個文件來實現,因為vector要嚴格用模板來實現,模板的聲明和定義不能分離到兩個文件。
淺品STL源碼
在自己模擬實現之前,先看一下它的源碼吧,但是小編目前功力不足,只能帶大家看一部分。 首先看它的成員函數:
iterator start;
iterator finish;
iterator end_of_storage;
嗯?三個迭代器?這和string完全不一樣啊,快去看看這些迭代器是什么:
typedef T value_type;
typedef value_type* iterator;
哦,原來就是原始指針啊,那就猜一下start就是指向數組首元素的指針,finish是指向有效數據結尾下一個位置的指針,end_of_storage是指向空間末尾的指針,那事實是不是這樣呢,接下來應該去找begin()和end()和capacity():
iterator begin() { return start; }
iterator end() { return finish; }
size_type capacity() const { return size_type(end_of_storage - begin()); }
看來猜的大差不差,接下來就開始模擬實現vector吧。
構造函數
vector()
{ }
拷貝構造
vector(const vector<T>& v){reserve(v.capacity());for (auto e : v){push_back(e);}}
拷貝構造本質就是一個對象想要另一個對象一樣大的空間一樣的值,所以可以復用reserve來開空間,再用范圍for遍歷把數據全部拷貝過來。
但是這里要注意一個細節,在拷貝構造之前需要把成員變量初始化,如果不初始化的話在有些編譯器里就會默認是隨機值,然后capacity()來調用這些隨機值就會出錯,這里我們初始化方法推薦在成員變量處給隨機值。
那既然我們已經給了缺省值了,為什么前面還要實現一個默認構造函數呢,我們不寫它直接用缺省值不就行了嗎?其實就算它沒有實質用處,也還是要寫它,構造函數規定只要顯示寫了構造函數那么編譯器就不會生成默認構造了,我們寫了的拷貝構造就是構造函數,所以如果不寫前面那個默認構造函數的話我們就無法調用默認構造函數了。
除了自己寫之外我們還可以強制編譯器生成默認構造:
vector() = default;
多參數構造
vector(initializer_list<T> i1){reserve(i1.size());for (auto e : i1){push_back(e);}}
這里就可以用前面介紹的initializer_list來實現多參數構造。
迭代器區間構造
這里我們可以用函數模板,如果我們寫死為iterator的嗎那只有vector能調用這里的迭代器區間構造,如果我們寫成模板那其他類對象比如string的迭代器也能構造初始化,但是要數據類型匹配,比如字符就可以轉化成這里vector實例化出的整型。
也就是說類模板的成員函數還可以繼續寫成函數模板。
template <class InputIterator>vector(InputIterator first, InputIterator last){reserve(last - first);while (first != last){push_back(*first);first++;}}
n個val初始化
這個構造用的也挺多,比如前面講的楊輝三角。
這里還要注意參數匹配,不匹配的話會調到迭代器區間初始化去。
vector(int n, const T& val = T()){reserve(n);resize(n, val);}
swap
void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}
operator=
vector<T>& operator=(vector<T>& v){swap(v);return *this;}
這里就是我們在string部分介紹的現代寫法。
reserve
void reserve(size_t n){//若外部調用該函數需要判斷if (n > capacity()){size_t old_size = size();//開新空間T* tmp = new T[n];//拷貝舊空間數據到新空間,并釋放舊空間//若_start為0(nullptr),無需拷貝if (_start){//memcpy會引發深層次的深拷貝問題//memcpy(tmp, _start, sizeof(T) * old_size);for (int i = 0; i < old_size; i++){tmp[i] = _first[i];}delete[] _start;}_start = tmp;_finish = _start + old_size;_endofstorage = _start + n;}}
這里要提前把舊對象size()值保存下來,避免后面調用size() {return _finish - _first;}其中一個是舊的數據,一個是更新后的數據,結果不是我們想要的。
注意拷貝數據時不能用nencpy,詳細解釋見深層次的深拷貝問題。
size
//不改變調用對象的函數加const
size_t size() const
{return _finish - _first;
}
capacity
size_t capacity() const
{return _endofstorage - _first;
}
push_back(補充解釋源碼里為什么要用定位new)
void push_back(const T& x)
{if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;finish++;
}
這里我們直接就把x的值賦給finish所在位置了,因為我申請的空間是直接new出來的,不僅開辟了空間,還調用了構造函數初始化這塊空間,所以不管x是內置類型還是自定義類型,都可以直接賦值。
但是源碼里的vector空間不是直接在堆上new的,而是在內存池里malloc的空間,所以空間是沒有初始化的,若空間里是自定義類型的變量,直接賦值就會出問題:
我們以string為例,先看我們實現的string的賦值運算符重載:
string& string::operator=(const string& s) {if (*this != s){char* tmp = new char[s._size + 1];memcpy(tmp, s._str, s._size + 1);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}
這里我們用沒初始化的s直接調用賦值運算符重載就會出問題,因為沒初始化的s的成員變量都是隨機值,比方說new char[s._size +
1]這里的_size就是隨機值,那么它最終new了多少數據就是未知的,和我們的想法違背。
所以源碼里還使用了定位new用來顯示調用構造函數,避免出現上面的情況。
迭代器
typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _first;}iterator end(){return _finish;}const_iterator begin() const{return _first;}const_iterator end() const{return _finish;}
普通迭代器和const迭代器都要實現,以便const對象調用。
pop_back
bool empty(){return _finish == _first;}void pop_back(){assert(!empty());_finish--;}
pop_back不用刪除數據,只用把_finish–就行了,但是要注意判斷數組是否為空。
insert(補充迭代器失效)
iterator insert(iterator pos, const T& x){assert(pos >= _first && pos <= _finish);//擴容if (_finish == _endofstorage){size_t len = pos - _first;reserve(capacity() == 0 ? 4 : 2 * capacity());//更新pospos = _first + len;}//挪動數據iterator end = _finish;while (end >= pos){*(end + 1) = *end;end--;}//插入數據*pos = x;_finish++;return pos;}
這里返回值為什么是迭代器,在后面erase部分再展開講解。
乍一看這段代碼非常完美,其實潛藏了一個坑點,當數組空間不夠要擴容時,因為是堆上的空間,所以大概率會異地擴,那么擴完之后_first和_finish都指向新空間了,但是pos還指向舊空間,pos不就成野指針了嗎,其實這里說是野指針并不準確,官方來講應該是迭代器失效,因為這里迭代器恰好就是原生指針,其他容器并不一定。
解決方法:只需要每次擴容的時候更新pos就行了,運用指針的相對位置,先用len記錄pos到_first的距離,擴容后_first+len就得到更新后的pos了。
優化后:
void pop_back(){assert(!empty());_finish--;}void insert(iterator pos, const T& x){assert(pos >= _first && pos <= _finish);//擴容if (_finish == _endofstorage){size_t len = pos - _first;reserve(capacity() == 0 ? 4 : 2 * capacity());//更新pospos = _first + len;}//挪動數據iterator end = _finish;while (end >= pos){*(end + 1) = *end;end--;}//插入數據*pos = x;_finish++;}
我們再來看下面這段代碼:
int x;cin >> x;auto it = find(v.begin(), v.end(), 4);if (it != v.end()){v.insert(it, x * 10);//it是否還能用?}
意思是我們隨便輸入一個x,然后再v里找是否有x,有的話在它前面插入10x。 這里我們想想插入過后迭代器it是否還能用?(因為標準沒有規定何時擴容,所以這里一致認為insert后擴容了并且導致迭代器失效)
有的讀者可能會認為當然可以啊,it的數據都更新了,但是其實是不行的,因為更新的只是形參pos,這里只是傳值所以形參的改變不會影響實參。
那直接把insert的第一個參數類型改為iterator&不就行了嗎,其實這也是不對的,比如下面:
v.insert(v.begin(), 30);
v.insert(it + 2, 30);
用begin函數調用insert,我們前面實現begin函數是傳值返回的_first,所以返回的并不是_first本身,而是它的一份臨時拷貝,那如果這里insert引用了這個返回值,就會發生權限的放大,第二鐘情況也是同理,it + 2表達式的的結果也是臨時對象,具有常性的。所以小編在這里提醒大家,縱使引用有萬般好,也要視情況用。
erase
void erase(iterator pos){assert(pos >= _first && pos < _finish);auto it = pos + 1;//挪動數據while (it != _finish){*(it - 1) = *it;it++;}_finish--;}//優化后iterator erase(iterator pos){assert(pos >= _first && pos < _finish);auto it = pos + 1;//挪動數據while (it != _finish){*(it - 1) = *it;it++;}_finish--;return pos;}
實現思路就是把目標位置以后的數據往前挪,開頭的assert也能檢查數組是否為空。
那erase后迭代器是否會失效呢?我們來看下面這段程序:
std::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);//刪除偶數auto it = v.begin();while (it != v.end()){if ((*it) % 2 == 0){v.erase(it);//it是否失效?}it++;}
這段代碼會刪除v里面的的偶數數據。我們分析一下,第一次會刪除2,然后后面數據依次往前挪,以前指向2的迭代器就被動指向3了,這里就出現迭起器失效的問題了,因為指向的內容被改變了,因為vs對迭代器失效進行了嚴格檢驗,所以迭代器失效后再對這個迭代器訪問會直接報錯,但是在g++下就能通過,因為不同編譯器對迭代器失效的處理是不同的,總的來說,這里是有問題的。
并且這里還有一個隱藏問題,就是刪除2了之后,所有數據往前挪,那此時迭代器就指向3了,it++后就指向4了,相當于3沒判斷直接跳過了。
解決方法標準已經給出了,我們來看標準庫的erase:
它給了一個返回值iterator,它返回的是刪除元素位置下一個位置的迭代器,這就是方便我們來賦值更新迭代器的,也就是用it接受這個返回值就達到了更新迭代器的目的,這樣就。完美解決了迭代器失效的問題。
優化后:
auto it = v.begin();while (it != v.end()){if ((*it) % 2 == 0){it = v.erase(it);}else{it++;}}
總結:無論insert還是erase都會造成迭代器失效,因為它們有中間迭代器參數pos,解決辦法就是迭代器失效后及時更新迭代器。
clear
void clear(){_finish = _start;}
這里只能把_start賦值給_finish,因為_start必須指向空間的開始,clear不用釋放空間,交給析構函數來釋放。
resize
在介紹resize之前,小編想先講一下C++標準因為支持模板,所以它還支持了內置類型的構造函數,所以下面這些代碼都是支持的:
int i = 10;int j(10);int k = int();int m = int(10);
接下的resize的缺省參數就會用到。
void resize(size_t n, T val = T()){if (n > size()){reserve(n);while (_finish != _start + n){(*_finish) = val;_finish++;}}else{_finish = _start + n;}}
這里resize第二個參數是模板,所以就不能像以前一樣用0充當缺省值,這里最好就是用匿名對象T()當缺省值,(其實匿名對象就是調用了默認構造,因為默認構造就是不傳實參也可以調用的構造)不管是內置類型還是自定義類型的默認構造的值都接近與0,int就是0,char就是ASCII碼為0的’\0’,這樣不管參數是內置類型還是自定義類型都可以調用。
深層次的深拷貝問題
wusaqi::vector<string> v1;v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");print(v1);
這段代碼是用string來實例化vector,我們分別來看vector擴容前和擴容后打印出來的值:
我們看到在擴容后數組的前四個vector被置成隨機值了,敏銳一點的讀者應該會感覺是淺拷貝之類的問題。事實確實是這樣。我們既然知道是擴容后發生的問題,那我們來看擴容接口:
void reserve(size_t n){//若外部調用該函數需要判斷if (n > capacity()){size_t old_size = size();//開新空間T* tmp = new T[n];//拷貝舊空間數據到新空間,并釋放舊空間//若_start為0(nullptr),無需拷貝if (_start){memcpy(tmp, _start, sizeof(T) * old_size);delete[] _start;}_start = tmp;_finish = _start + old_size;_endofstorage = _start + n;}}
這里拷貝數據是memcpy,我們知道memcpy只會一個字節一個字節拷貝,相當于它會原封不動的把string的成員變量:_str _size _caoacity拷貝到tmp,也就是說tmp數組里的string成員變量_str和原數組里的string成員變量_str的值是一樣的,指向同一塊空間,那么調用delete釋放原數組后tmp數組里的值也被釋放了,所以就解釋了為什么擴容后前四個string為隨機值。
我們借用監視窗口可以看到底層數組確實是指向同一塊空間:
這里問題就出在reserve的拷貝上,解決思路很簡單,我們不用memcpy,而是for循環遍歷把每一個數組里的元素然后用賦值運算符重載把元素依次賦給tmp數組,這樣內置類型正常淺拷貝賦值,自定義類型就會去調用自己的賦值運算符重載完成深拷貝。
void reserve(size_t n){//若外部調用該函數需要判斷if (n > capacity()){size_t old_size = size();//開新空間T* tmp = new T[n];//拷貝舊空間數據到新空間,并釋放舊空間//若_start為0(nullptr),無需拷貝if (_start){//memcpy會引發深層次的深拷貝問題//memcpy(tmp, _start, sizeof(T) * old_size);for (int i = 0; i < old_size; i++){tmp[i] = _first[i];}delete[] _start;}_start = tmp;_finish = _start + old_size;_endofstorage = _start + n;}}
源碼
vector.h
#pragma once
#include <assert.h>
#include <string.h>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;namespace wusaqi
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}vector(){}//vector() = default;vector(const vector<T>& v){reserve(v.capacity());for (auto e : v){push_back(e);}}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}vector<T>& operator=(vector<T>& v){swap(v);return *this;}vector(initializer_list<T> i1){reserve(i1.size());for (auto e : i1){push_back(e);}}template <class InputIterator>vector(InputIterator first, InputIterator last){reserve(last - first);while (first != last){push_back(*first);first++;}}vector(int n, const T& val = T()){reserve(n);resize(n, val);}vector(size_t n, const T& val = T()){reserve(n);resize(n, val);}~vector(){if (_start){delete[] _start;_start = _finish = _endofstorage = nullptr;}}void reserve(size_t n){//若外部調用該函數需要判斷if (n > capacity()){size_t old_size = size();//開新空間T* tmp = new T[n];//拷貝舊空間數據到新空間,并釋放舊空間//若_start為0(nullptr),無需拷貝if (_start){//memcpy會引發深層次的深拷貝問題//memcpy(tmp, _start, sizeof(T) * old_size);for (int i = 0; i < old_size; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + old_size;_endofstorage = _start + n;}}T& operator[](size_t i){//斷言防止越界訪問assert(i < size());return _start[i];}//不改變調用對象的函數加constsize_t size() const{return _finish - _start;}size_t capacity() const{return _endofstorage - _start;}void push_back(const T& x){//size_t storage = capacity();//if (_finish == _endofstorage)//{// size_t newstorage = storage == 0 ? 4 : 2 * storage;// reserve(newstorge);//}//簡化:if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;_finish++;}bool empty(){return _finish == _start;}void pop_back(){assert(!empty());_finish--;}iterator insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);//擴容if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());//更新pospos = _start + len;}//挪動數據iterator end = _finish;while (end >= pos){*(end + 1) = *end;end--;}//插入數據*pos = x;_finish++;return pos;}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);auto it = pos + 1;//挪動數據while (it != _finish){*(it - 1) = *it;it++;}_finish--;return pos;}void clear(){_start = _finish;}void resize(size_t n, const T& val = T()){if (n > size()){reserve(n);while (_finish != _start + n){(*_finish) = val;_finish++;}}else{_finish = _start + n;}//size_t capacity = _endofstorage - _start;//size_t size = _finish - _start;//if (n < size)//{// _finish = _start + n;//}//else//{// if (n > capacity)// {// reserve(n);// _endofstorage = _start + n;// }// iterator pos = _finish;// while (pos != _start + n)// {// (*pos) = val;// pos++;// }// _finish = _start + n;//}}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "vector.h"template<class T>
void print(const T& v)
{for (auto ch : v){cout << ch << " ";}cout << endl;
}void test01()
{wusaqi::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.pop_back();for (int i = 0; i < v.size(); i++){cout << v[i] << " ";}cout << endl;for (auto ch : v){cout << ch << " ";}cout << endl;print(v);
}void test02()
{wusaqi::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);//v.push_back(5);v.insert(v.begin(), 30);print(v);//v.erase(v.begin() + 2);//print(v);int x;cin >> x;wusaqi::vector<int>::iterator it = find(v.begin(), v.end(), x);if (it != v.end()){v.erase(it);}print(v);}void test03()
{wusaqi::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(5);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(4);print(v);//刪除偶數auto it = v.begin();while (it != v.end()){if ((*it) % 2 == 0){it = v.erase(it);}else{it++;}}print(v);v.clear();print(v);
}void test04()
{wusaqi::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(5);v.push_back(2);v.push_back(3);v.push_back(4);v.push_back(5);v.push_back(4);print(v);v.resize(10, 100);print(v);//int i = 10;//int j(10);//int k = int();//int m = int(10);
}void test05()
{wusaqi::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);print(v1);wusaqi::vector<int> v2(v1);print(v2);wusaqi::vector<int> v3 = { 1, 2, 3, 4, 5, 1, 1, 1 };print(v3);wusaqi::vector<int> v4(v3.begin() + 2, v3.end() - 2);print(v4);string s1("good morning");wusaqi::vector<int> v5(s1.begin() + 2, s1.end() - 2);print(v5);std::vector<int> v6(10, 1);print(v6);std::vector<size_t> v7(10, 1);print(v7);
}void test06()
{wusaqi::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);print(v1);wusaqi::vector<int> v3;v3 = v1;print(v3);
}void test07()
{wusaqi::vector<string> v1;v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");v1.push_back("1111111111111111111111");print(v1);
}int main()
{//test01();//cout << typeid(std::vector<int>::iterator).name() << endl;//cout << typeid(wusaqi::vector<int>::iterator).name() << endl;//test02();//test03();//test04();test05();//test06();//test07();return 0;
}
以上就是小編分享的全部內容了,如果覺得不錯還請留下免費的關注和收藏
如果有建議歡迎通過評論區或私信留言,感謝您的大力支持。
一鍵三連好運連連哦~~