目录
一、模拟实现接口总览
1.1 接口总览
Memberfunctions//构造函数vector() //拷贝构造 -- 现代写法2vector(constvector<T>&v) //迭代器区间构造template<classInputIterator>vector(InputIteratorfirst, InputIteratorlast) //n个val构造vector(size_tn, constT&val=T()) //n个val构造 -- 重载,解决第一个参数的int size_t 的问题vector(intn, constT&val=T()) //析构~vector() //赋值重载 -- 现代写法2vector<T>&operator=(vector<T>v) //iteratoriteratorbegin() iteratorend() const_iteratorbegin()constconst_iteratorend()const//capacitysize_tsize()constsize_tcapacity()constboolempty()constvoidreserve(size_tn) voidresize(size_tn, Tval=T()) //element accessT&operator[](size_tpos) constT&operator[](size_tpos)const//modifiervoidswap(vector<T>&v) voidpush_back(constT&x) voidpop_back() //任意位置插入 -- 插入后认为迭代器失效, 迭代器失效 : 扩容引起,野指针问题iteratorinsert(iteratorpos, constT&val) //任意位置删除 -- erase 之后也认为 pos 迭代器失效iteratorerase(iteratorpos)
上面也是挑一些常用的进行模拟实现,要把自己实现的写在自己命名的命名空间里面,否则与库中的 vector 会产生冲突
注:
vector类模拟实现,最主要也是实现 vector 的构造、拷贝构造、赋值运算符重载以及析构函数
1.2 vector整体框架
usingnamespacestd; namespacefy{ template<classT>classvector { public: //vector的迭代器是一个原生指针typedefT*iterator; typedefconstT*const_iterator; private: iterator_start;// 指向数据块的开始iterator_finish;// 指向数据块的结尾iterator_endOfStorage;//指向存储容量的尾 }; }
注:
后面的 STL 的模拟实现我们参考的是SGI版 STL3.0 的写法,写法跟上一个 string 模拟实现有所不同,虽然表面上看起来不一样,但是实际上表达的效果是大同小异的
1.3 vector成员变量介绍
在vector当中有三个成员变量_start、_finish、_endofstorage
- _start指向容器的头
- _finish指向容器当中有效数据的尾
- _endofstorage指向整个容器的尾
- 指针减指针 就可以得到大小或容量
- _finish - _start = size(有效数据的大小)
- _endOfStorage - _start = capacity(整个容器的容量)
二、vector模拟实现
2.1 构造函数
2.1.1 无参构造
这里要完成的工作是初始化,直接将构造对象的三个成员变量都设置为 nullptr
//构造函数vector() :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) {}
2.1.2 迭代器区间构造
vector 支持使用一段迭代器区间进行对象的构造,但是这里要注意:该迭代器区间可以是其他容器的迭代器区间,也就是说该函数接收到的迭代器的类型是不确定的,所以我们这里需要将该构造函数设计为一个函数模板,然后再将数据一个个尾插即可
//迭代器区间构造template<classInputIterator>//模板函数vector(InputIteratorfirst, InputIteratorlast) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { while (first!=last)//尾插 { push_back(*first); ++first; } }
2.1.3 n个val构造
vector 也支持 n 个 val 构造,比如构造10个1。对于该函数,可以先利用 reserve 进行扩容,一次性开好所需要的空间,然后进行尾插即可
//n个val构造vector(size_tn, constT&val=T()) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { reserve(n);//扩容for (size_ti=0;i<n; ++i)//把数据进行尾插 { push_back(val); } }
2.1.3 n个val构造
vector 也支持 n 个 val 构造,比如构造10个1。对于该函数,可以先利用 reserve 进行扩容,一次性开好所需要的空间,然后进行尾插即可
//n个val构造vector(size_tn, constT&val=T()) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { reserve(n);//扩容for (size_ti=0;i<n; ++i)//把数据进行尾插 { push_back(val); } }
但是,这里存在一个问题,执行这句代码时直接报错
fy::vector<int> v5(10, 2);
这是因为 这句代码调用的不是 n个 val构造,而是调用了迭代器区间构造,迭代器区间构造对参数 first 和 last 进行了解引用,而 int类型不能进行解引用操作,所以报错说非法寻址
造成这个的直接原因是 n 个 val构造的第一个参数 size_t ,与 fy::vector v5(10, 2) 第一个参数类型不匹配,编译器就会优先调用迭代器区间构造,要解决这个问题可以对 v5(10, 2) 第一个参数强制类型转化成 size_t,但是这样会给使用者不舒服,另一种就是函数重载
//n个val构造 -- 重载,解决第一个参数的int size_t 的问题vector(intn, constT&val=T()) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { reserve(n); for (inti=0; i<n; ++i) { push_back(val); } }
2.1.4 拷贝构造
拷贝构造也分传统写法和现代写法,推荐现代写法,注意深浅拷贝的问题,这里明显就是要进行深拷贝
(1)传统写法
思想:先开辟一块与该容器大小相同的空间,然后将该容器当中的数据拷贝过来
拷贝构造//传统写法vector(constvector<T>&v) { T*tmp=newT[v.capacity()];//开辟一块大小相同的空间memcpy(tmp, v._start, sizeof(T) *v.capacity());//拷贝_start=tmp;//更新_start_finish=_start+v.size();//更新_finish_endOfStorage=_start+v.capacity();//更新_endOfStorage}
但是这里存在一个严重的问题,当 vector 存储的数据是内置类型或无需进行深拷贝的自定义类型时,使用 memcpy 函数是没什么问题的,但当vector存储的数据是需要进行深拷贝的自定义类型时,使用 memcpy 函数的弊端就体现出来
比如:vector 存储的数据是 string 时
vector 里面的每个储存对象都是 string,并且 string 也指向自己所开辟的空间,即指向自己储存的字符串
使用 memcpy 函数进行拷贝构造的话,那么拷贝构造出来的 vecto r当中存储的每个 string 的成员变量的值,将与被拷贝的vector当中存储的每个 string 的成员变量的值相同,即两个vector当中的每个对应的string成员都指向同一个字符串空间,进行析构的时候就会出问题,string 指向的空间会被释放两次
如何解决?一个个进行深拷贝就可以了
vector(constvector<T>&v) { _start=newT[v.capacity()];//开辟一块大小相同的空间for (size_ti=0; i<v.size(); i++) //将容器v当中的数据一个个拷贝过来 { _start[i] =v[i];//利用了赋值重载 } _finish=_start+v.size();//更新_finish_endOfStorage=_start+v.capacity();//更新_endOfStorage}
这里利用了 string类的赋值重载,string类的赋值运算符重载函数就是深拷贝
拷贝完了之后结果是:
这样就完成了深拷贝
所以,C语言的关于内存接口直接使用大多数是有问题的,尽量少使用 C语言的关于内存方面接口,C语言的关于内存方面接口对内置类型无影响,对自定义类型的影响就很大了
(2)现代写法
复用迭代器区间构造,再交换一下数据即可
//拷贝构造 -- 现代写法vector(constvector<T>&v) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { vector<T>tmp(v.begin(), v.end()); swap(tmp); }
注:swap 后面实现
2.2 赋值运算符重载
vector 的赋值运算符重载也涉及深拷贝问题,也有传统写法和现代写法
2.2.1 传统写法
判断是否是给自己赋值,若是给自己赋值则无需进行操作;若不是给自己赋值,则先开辟一块和 v 大 小相同的空间,然后将容器 v 当中的数据拷贝
赋值重载//传统写法vector<T>&operator=(constvector<T>&v) { if (this==&v) { return*this;//检查自我赋值 } delete[] _start; T*tmp=newT[v.capacity()]; memcpy(tmp, v._start, sizeof(T) *v.capacity());//拷贝_start=tmp; _finish=_start+v.size(); _endOfStorage=_start+v.capacity(); return*this; }
这里也是 memcpy 这个问题,跟上面一样,也是利用 赋值重载,一个个进行深拷贝就可以了
vector<T>& operator=(const vector<T>& v) { if (this == &v) { return *this;//检查自我赋值 } delete[] _start; _start = new T[v.capacity()];//开空间,与v一致 for (size_t i = 0; i < v.size(); i++) //将容器v当中的数据一个个拷贝过来 { _start[i] = v[i]; } _finish = _start + v.size(); _endOfStorage = _start + v.capacity(); return *this; }
2.2.2 现代写法
(1)现代写法1
复用拷贝构造,构造出 tmp,然后交换一下就可以了
//赋值重载 -- 现代写法1vector<T>&operator=(constvector<T>&v) { if (this==&v) { return*this;//检查自我赋值 } vector<T>tmp(v);//复用拷贝构造swap(tmp);//复用swapreturn*this; }
(2)现代写法2
也是复用拷贝构造,但是参数不再是传引用传参,而是传值形参,而传值传参则会自动调用拷贝构造函数,但是这种写法无法检查自我赋值的情况,但是这种情况几乎不会出现,推荐这种写法
//赋值重载 -- 现代写法2vector<T>&operator=(vector<T>v)//传值传参自动调用拷贝构造,不能检查自我赋值的问题,但不影响程序正确性{ swap(v); return*this; }
2.3 析构函数
释放空间,置空即可
//析构~vector() { delete[] _start; _start=_finish=_endOfStorage=nullptr; }
2.4 Iterator
vector 的迭代器实际上也是指针,范围 for 底层也是迭代器
//vector的迭代器是一个原生指针typedefT*iterator; typedefconstT*const_iterator;
2.4.1 begin
返回容器的首地址即可
//iteratoriteratorbegin() { return_start; }
2.4.1 begin
返回容器的首地址即可
//iteratoriteratorbegin() { return_start; }
const 版本的,只能对数据进行读操作,而不能进行修改
const_iteratorbegin()const{ return_start; }
2.4.2 end
返回容器当中有效数据的下一个数据的地址
iteratorend() { return_finish; }
2.4.2 end
返回容器当中有效数据的下一个数据的地址
iteratorend() { return_finish; }
const 版本的,只能对数据进行读操作,而不能进行修改
const_iteratorend()const{ return_finish; }
2.5 Capacity
2.5.1 size
返回数据个数,指针相减即可
size_tsize()const{ return_finish-_start; }
2.5.2 capacity
返回容器实际容量,指针相减即可
size_tcapacity()const{ return_endOfStorage-_start; }
2.5.2 capacity
返回容器实际容量,指针相减即可
size_tcapacity()const{ return_endOfStorage-_start; }
2.5.3 empty
直接通过比较容器当中的_start和_finish指针的指向来判断容器是否为空,若所指位置相同,则该容器为空
boolempty()const{ return_start==_finish; }boolempty()const{ return_start==_finish; }
2.5.4 resize
resize 规则:
- 当所给值 n大于容器当前的 size时,将size扩大到 n,扩大的元素为第二个所给值 val,若未给出,则默认为容器所存储类型的默认构造函数所构造出来的值
- 当所给值 n小于容器当前的 size时,将size缩小到 n
voidresize(size_tn, Tval=T()) voidresize(size_tn, Tval=T()) { if (n>capacity())//检查是否需要扩容 { reserve(n); } if (n>size()) { while (_finish<_start+n) { *_finish=val; ++_finish; } } else { _finish=_start+n;//n < size,有效数据缩减 } }
第二个参数,默认给的是其对应类型的缺省值作为 "填充值"。由于这里我们不知道具体类型是什么,这里缺省值我们使用匿名对象 T(),使用匿名对象后 val 为容器所存储类型的默认构造函数所构造出来的值
2.5.5 reserve
reserve 规则:
- n大于对象当前的 capacity时,将capacity扩大到n或大于n
- n小于对象当前的 capacity时,什么也不做,也不缩容
voidreserve(size_tn) { if (n>capacity())//n大于 capacity 才扩容,reserve不缩容 { size_toldSize=size(); T*tmp=newT[n]; if (_start) { //memcpy对自定义类型会有浅拷贝问题,需要对每个元素使用拷贝构造进行深拷贝//memcpy(tmp, _start, sizeof(T) * oldSize);//errordelete[] _start; } _start=tmp; _finish=tmp+oldSize; _endOfStorage=_start+n; } }
这里也是 memcpy 这个问题,跟上面一样,也是利用 赋值重载,一个个进行深拷贝就可以了
voidreserve(size_tn) { if (n>capacity())//n大于 capacity 才扩容,reserve不缩容 { size_toldSize=size();//记录原来的size,避免扩容不能确定 _finishT*tmp=newT[n]; if (_start) { for (size_ti=0; i<oldSize; ++i) { tmp[i] =_start[i];//利用赋值重载 } delete[] _start; } _start=tmp; _finish=tmp+oldSize; _endOfStorage=_start+n; } }
2.6 element access
2.6.1 operator[]
vector也支持我们使用 “下标+[ ]” 的方式对容器当中的数据进行访问,实现时直接返回对应位置的数据即可
T&operator[](size_tpos) { assert(pos<size()); return_start[pos]; }
const 版本,只读,不能对数据进行修改
constT&operator[](size_tpos)const{ assert(pos<size()); return_start[pos]; }
2.7 Modifiers
2.7.1 swap
swap 函数用于交换两个容器的数据,直接调用库当中的 swap 函数将两个容器当中的各个成员数据进行交换即可
voidswap(vector<T>&v) { std::swap(_start, v._start);//使用库里面的 swap 函数std::swap(_finish, v._finish); std::swap(_endOfStorage, v._endOfStorage); }
2.7.2 push_back
注意判断数据是否满,直接在尾上插入数据即可
voidpush_back(constT&x) { if (_finish==_endOfStorage) { size_tnewCapacity=capacity() ==0?4 : capacity() *2; reserve(newCapacity); } *_finish=x; ++_finish; }
2.7.3 pop_back
尾删数据,注意判空
1. void pop_back() 2. { 3. assert(!empty()); 4. --_finish; 5. }
2.7.4 insert
这里要注意迭代器失效的问题,insert函数可以在所给迭代器pos位置插入数据,分四步:① 检查 pos 是否越界 ② 检查是否需要扩容 ③ 移动数据 ④ 插入数据
//任意位置插入 -- 插入后认为迭代器失效, 迭代器失效 : 扩容引起,野指针问题iteratorinsert(iteratorpos, constT&val) { assert(pos>=_start&&pos<_finish); //扩容会导致迭代器失效/*if (size() == capacity()){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*/if (size() ==capacity()) { size_tlen=pos-_start; size_tnewCapacity=capacity() ==0?4 : capacity() *2; reserve(newCapacity); // 扩容会导致pos迭代器失效,需要更新处理一下pos=_start+len; } iteratorend=_finish-1; while (end>=pos)//挪动数据 { *(end+1) =*(end); --end; } *pos=val; ++_finish; returnpos; }
2.7.5 erase
这里也要注意迭代器失效的问题,erase函数可以删除所给迭代器pos位置的数据
//任意位置删除 -- erase 之后也认为 pos 迭代器失效iteratorerase(iteratorpos) { assert(pos>=_start&&pos<_finish); iteratorbegin=pos+1; while (begin<_finish)//挪动数据 { *(begin-1) =*(begin); ++begin; } --_finish; returnpos; }
注:此处没有新开辟空间,也就没有野指针问题,erase 缩容也可能导致 pos 迭代器失效(具体看编译器实现),SGI版不缩容
看一下文档对 erase 返回值的描述,返回被删除位置的后一个位置的迭代器,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是没有元素的,那么pos就失效了,所以统一认为 erase 之后 pos 迭代器失效
迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃) 对于 vector对于 vector可能会导致其迭代器失效的操作有
- 会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等
- 指定位置元素的删除操作:erase
vector 的模拟实现两大问题:深拷贝和迭代器失效
而 string 模拟实现的时候并不注意迭代器失效这个问题,因为 string 大多数用的都是下标进行各项操作,基本不用迭代器进行操作,所以就忽略了
三、vector模拟实现全部代码
vector.h
usingnamespacestd; namespacefy{ template<classT>classvector { public: //vector的迭代器是一个原生指针typedefT*iterator; typedefconstT*const_iterator; //构造函数vector() :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) {} //拷贝构造传统写法//vector(const vector<T>& v)//{// _start = new T[v.capacity()];//开辟一块大小相同的空间// for (size_t i = 0; i < v.size(); i++) //将容器v当中的数据一个个拷贝过来// {// _start[i] = v[i];// }// _finish = _start + v.size();//更新_finish// _endOfStorage = _start + v.capacity();//更新_endOfStorage//}//vector(const vector<T>& v)//{// T* tmp = new T[v.capacity()];//开辟一块大小相同的空间// memcpy(tmp, v._start, sizeof(T) * v.capacity());//拷贝,error// _start = tmp;//更新_start// _finish = _start + v.size();//更新_finish// _endOfStorage = _start + v.capacity();//更新_endOfStorage//}//拷贝构造 -- 传统写法2/*vector(const vector<t>& v):_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){reserve(v.capacity());for (const auto& e : v){push_back(e);}}*///拷贝构造 -- 现代写法vector(constvector<T>&v) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { vector<T>tmp(v.begin(), v.end()); swap(tmp); } //迭代器区间构造template<classInputIterator>//模板函数vector(InputIteratorfirst, InputIteratorlast) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { while (first!=last)//尾插 { push_back(*first); ++first; } } //n个val构造vector(size_tn, constT&val=T()) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { reserve(n);//扩容for (size_ti=0;i<n; ++i)//把数据进行尾插 { push_back(val); } } //n个val构造 -- 重载,解决第一个参数的int size_t 的问题vector(intn, constT&val=T()) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { reserve(n); for (inti=0; i<n; ++i) { push_back(val); } } //析构~vector() { delete[] _start; _start=_finish=_endOfStorage=nullptr; } //赋值重载传统写法//vector<T>& operator=(const vector<T>& v)//{// if (this == &v)// {// return *this;//检查自我赋值// }// delete[] _start;// _start = new T[v.capacity()];//开空间,与v一致// for (size_t i = 0; i < v.size(); i++) //将容器v当中的数据一个个拷贝过来// {// _start[i] = v[i];// }// // _finish = _start + v.size();// _endOfStorage = _start + v.capacity();// return *this;//}//vector<T>& operator=(const vector<T>& v)//{// if (this == &v)// {// return *this;//检查自我赋值// }// delete[] _start;// T* tmp = new T[v.capacity()];// memcpy(tmp, v._start, sizeof(T) * v.capacity());// _start = tmp;// _finish = _start + v.size();// _endOfStorage = _start + v.capacity();// return *this;//}赋值重载--现代写法1//vector<T>& operator=(const vector<T>& v)//{// if (this == &v)// {// return *this;//检查自我赋值// }// vector<T> tmp(v);//复用拷贝构造// swap(tmp);//复用swap// return *this;//}//赋值重载 -- 现代写法2vector<T>&operator=(vector<T>v)//传值传参自动调用拷贝构造,不能检查自我赋值的问题,但不影响程序正确性 { swap(v); return*this; } //-------------------------------------------------------------//iteratoriteratorbegin() { return_start; } iteratorend() { return_finish; } const_iteratorbegin()const { return_start; } const_iteratorend()const { return_finish; } //-------------------------------------------------------------//capacitysize_tsize()const { return_finish-_start; } size_tcapacity()const { return_endOfStorage-_start; } boolempty()const { return_start==_finish; } voidreserve(size_tn) { if (n>capacity())//n大于 capacity 才扩容,reserve不缩容 { size_toldSize=size();//记录原来的size,避免扩容不能确定 _finishT*tmp=newT[n]; if (_start) { for (size_ti=0; i<oldSize; ++i) { tmp[i] =_start[i];// } delete[] _start; } _start=tmp; _finish=tmp+oldSize; _endOfStorage=_start+n; } //if (n > capacity())//n大于 capacity 才扩容,reserve不缩容//{// size_t oldSize = size();// T* tmp = new T[n];// if (_start)// {// //memcpy对自定义类型会有浅拷贝问题,需要对每个元素使用拷贝构造进行深拷贝// //memcpy(tmp, _start, sizeof(T) * oldSize);//error// delete[] _start;// }// _start = tmp;// _finish = tmp + oldSize;// _endOfStorage = _start + n;//} } voidresize(size_tn, Tval=T()) { if (n>capacity())//检查是否需要扩容 { reserve(n); } if (n>size()) { while (_finish<_start+n) { *_finish=val; ++_finish; } } else { _finish=_start+n;//n < size,有效数据缩减 } } //-------------------------------------------------------------//element accessT&operator[](size_tpos) { assert(pos<size()); return_start[pos]; } constT&operator[](size_tpos)const { assert(pos<size()); return_start[pos]; } //-------------------------------------------------------------//Modifiersvoidswap(vector<T>&v) { std::swap(_start, v._start);//使用库里面的 swap 函数std::swap(_finish, v._finish); std::swap(_endOfStorage, v._endOfStorage); } voidpush_back(constT&x) { if (_finish==_endOfStorage) { size_tnewCapacity=capacity() ==0?4 : capacity() *2; reserve(newCapacity); } *_finish=x; ++_finish; } voidpop_back() { assert(!empty()); --_finish; } //任意位置插入 -- 插入后认为迭代器失效, 迭代器失效 : 扩容引起,野指针问题iteratorinsert(iteratorpos, constT&val) { assert(pos>=_start&&pos<_finish); //扩容会导致迭代器失效/*if (size() == capacity()){size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newCapacity);}*/if (size() ==capacity()) { size_tlen=pos-_start; size_tnewCapacity=capacity() ==0?4 : capacity() *2; reserve(newCapacity); // 扩容会导致pos迭代器失效,需要更新处理一下pos=_start+len; } iteratorend=_finish-1; while (end>=pos) { *(end+1) =*(end); --end; } *pos=val; ++_finish; returnpos; } //任意位置删除 -- erase之后也认为 pos 迭代器失效iteratorerase(iteratorpos) { assert(pos>=_start&&pos<_finish); iteratorbegin=pos+1; while (begin<_finish)//挪动数据 { *(begin-1) =*(begin); ++begin; } --_finish; returnpos; } private: iterator_start;// 指向数据块的开始iterator_finish;// 指向数据块的结尾iterator_endOfStorage;//指向存储容量的尾 }; }
Test.cpp
voidvectorTest() { //构造fy::vector<int>v1; v1.push_back(1); v1.push_back(2); v1.push_back(3); v1.push_back(4); v1.push_back(5); v1.push_back(6); for (size_ti=0; i<v1.size(); ++i) { cout<<v1[i] <<" "; } cout<<endl; fy::vector<int>::iteratorit=v1.begin(); while (it!=v1.end()) { cout<<*it<<" "; ++it; } cout<<endl; for (autoe : v1) { cout<<e<<" "; } cout<<endl; //拷贝构造cout<<"--拷贝--"<<endl; fy::vector<int>v2(v1); for (autoe : v2) { cout<<e<<" "; } cout<<endl; //赋值重载cout<<"--赋值重载--"<<endl; fy::vector<int>v3; v3=v1; for (autoe : v2) { cout<<e<<" "; } cout<<endl; //迭代器区间构造cout<<"--迭代器区间构造--"<<endl; fy::vector<int>v4(v1.begin(), v1.end()); for (autoe : v4) { cout<<e<<" "; } cout<<endl; v4.pop_back(); v4.pop_back(); v4.pop_back(); v4.pop_back(); v4.pop_back(); for (autoe : v4) { cout<<e<<" "; } cout<<endl; //n个val构造cout<<"--n个val构造--"<<endl; fy::vector<int>v5(10, 2); for (autoe : v5) { cout<<e<<" "; } cout<<endl; cout<<"----------"<<endl; fy::vector<char>v6(10, 'a'); for (autoe : v6) { cout<<e<<" "; } cout<<endl; v6.resize(15); for (autoe : v6) { cout<<e<<" "; } cout<<endl; v6.resize(5); for (autoe : v6) { cout<<e<<" "; } cout<<endl; v6.insert(v6.begin() +3, 'x'); v6.insert(v6.begin() +3, 'z'); v6.insert(v6.begin() +3, 'x'); for (autoe : v6) { cout<<e<<" "; } cout<<endl; v6.erase(v6.end() -1); v6.erase(v6.end() -1); v6.erase(v6.end() -1); v6.erase(v6.end() -1); for (autoe : v6) { cout<<e<<" "; } cout<<endl; } intmain() { vectorTest(); return0; }
----------------我是分割线---------------
文章到这里就结束了,下一篇即将更新