目录
这里我们先将每一个小模块分别实现,然后最终的汇总代码和测试代码在后面
一、vector容器的基本结构
#pragma once
#include <stdio.h>
#include <assert.h>
namespace zhuyuan
{
template<class T>
class vector
{
public:
private:
//_start是容器的初始位置
iterator _start;
//finish是最后一个数据的下一个位置
iterator _finish;
//_end_of_storage是我们整个vector的容量大小
iterator _end_of_storage;
};
}
二、vector容器的构造函数和析构函数
//空参构造器
vector()
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
}
//析构函数
~vector()
{
//析构的时候只要将整一个空间的首元素的地址传过去就可以了。
delete[] _start;
_start=_finish=_end_of_storage= nullptr;
}
三、迭代器
其实连续的空间的迭代器可以用指针来实现
typedef T* iterator;
const typedef T* const_iterator;
iterator begin()
{
return _start;
}
const iterator begin() const
{
return _start;
}
iterator end()
{
return _finish;
}
const iterator end() const
{
return _finish;
}
四、返回容器中的相关参数
_end_of_storage表示的是容器中当前开辟的空间的最后位置的迭代器。
_start表示的是当前的容器的首元素的位置
_finish表示的当前容器中最后一个元素的下一个位置
capacity表示的是当前容器的容量大小
size表示的是当前容器中存储的元素个数
size_t capacity() const
{
return _end_of_storage-_start;
}
size_t size() const
{
return _finish-_start;
}
五、交换函数
对我们两个容器中的每一个成员变量都进行交换,交换可以直接调用我们的std中的交换函数。
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._endOfStorage);
}
六、拷贝构造
1.拷贝指定范围的数据
//将要拷贝的迭代器的范围传入
vector(iterator first,iterator last)
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
reserve(last-first+1);
iterator it=begin();
for(int i=0;i<last-first;i++)
{
*it=*(first+i);
it++;
}
_finish=_start+(last-first);
}
测试代码
void myvector_test9()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
vector<int> v2(v1.begin(),v1.end());
cout<<v2[1]<<endl;
}
2.拷贝构造
vector(const vector<T>& v)
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(v.capacity());
iterator it = begin();
const_iterator vit = v.begin();
while (vit != v.end())
{
*it++ = *vit++;
}
_finish = it;
}
测试代码
void myvector_test8()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
vector<int> v2(v1);
vector<int>::iterator it=v2.begin();
while(it!=v2.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
}
3.使用=拷贝构造
这里我们可以采用和之前字符串中一样的老板式的写法
由于编译器在将v传过来的时候会拷贝构造一个v,将这个v与我们当前的容器中的内容交换一下,我们的当前容器就完成拷贝了
vector<T>&operator =(vector<T> v)
{
swap(v);
return *this;
}
void myvector_test10()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
vector<int> v2=v1;
vector<int>::iterator it1=v1.begin();
while(it1!=v1.end())
{
cout<<*it1<<" ";
it1++;
}
cout<<endl;
vector<int>::iterator it2=v2.begin();
while(it2!=v2.end())
{
cout<<*it2<<" ";
it2++;
}
cout<<endl;
}
七、扩容操作
1.reserve扩容
reserve如果传入的数据比当前的空间大小小的话是不会处理的。
//开辟n个空间
void reserve(size_t n)
{
if(n>capacity())
{
size_t sz=size();
T*tmp=new T[n];
if(_start)
{
memcpy(tmp,_start,sizeof(T)*size());
delete[] _start;
}
_start=tmp;
_finish=_start+sz;
//由于上面的过程中我们将原先的_start给销毁了,新的_start变成了tmp
//所以其size可能会发生变化,
// _finish=_start+size();
_end_of_storage=_start+n;
}
}
2.resize调整大小
//resize第一个参数是要调整到的大小,第二个参数是如果调整出来的大小大于了原来的数据用什么值填充
void resize(size_t n,const T&value=T())
{
//1.如果n小于当前的size,则数据个数缩小到n
if(n<=size())
{
_finish=_start+n;
return;
}
//2.空间不够则增容
if(n>capacity())
{
reserve(n);
}
//3.将size扩大到n
iterator it=_finish;
_finish=_start+n;
while(it!=_finish)
{
*it=value;
++it;
}
}
测试代码
void myvector_test11()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int>::iterator it1=v1.begin();
while(it1!=v1.end())
{
cout<<*it1<<" ";
it1++;
}
cout<<endl;
vector<int>v2=v1;
v1.resize(7,5);
vector<int>::iterator it2=v1.begin();
while(it2!=v1.end())
{
cout<<*it2<<" ";
it2++;
}
cout<<endl;
}
八、让我们的容器支持随机读写
我们分别需要提供const类型的和非const类型的。
const T&operator [](size_t pos) const
{
assert(pos<size());
return _start[pos];
}
T&operator [](size_t pos)
{
assert(pos<size());
return _start[pos];
}
九、尾插尾删
1.尾插push_back
尾插要注意扩容
//使用泛型,输入的是T类型
void push_back(const T&x)
{
if(_finish==_end_of_storage)
{
reserve(capacity()==0?4 :capacity()*2);
}
//finish是最后一个数据的下一个位置
*_finish=x;
++_finish;
}
2.尾删 pop_back
尾删我们需要先判断一下当前的容器还有没有元素
void pop_back()
{
assert(_finish>_start);
--_finish;
}
3.将容器后面追加n个元素,元素为value
vector<string> v;
// 如果下面的这个push_back不加const,就会报错,因为拷贝的这个字符串具有隐式类型转换
// 期间会生成一个中间的临时变量,而这个临时变量具有常性。如果不加const会发生权限的扩大。
// v.push_back("xxxx")
vector(size_t n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
测试代码
//使用迭代器遍历容器
void Func(const vector<int>&v)
{
vector<int>::const_iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
}
void myvector_test1()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//使用随机读取的方式遍历
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
//使用范围for的形式遍历容器
//有了迭代器就支持范围for,也就是调用我们的v.begin(),v.end()来执行相关的操作
//const的话就走const的迭代器,
for(auto e:v)
{
cout<<e<<" ";
}
v.pop_back();
cout<<endl;
Func(v);
}
十、随机位置插入和删除
1.随机位置插入insert
迭代器失效就是当我们尾插数据的时候,如果发生了扩容,原来的地址空间可能就被转换到了一块更大的空间,所以我们迭代器的指针就失效了。所以我们如果发生了扩容就要及时更新指针。
// void insert(iterator &pos ,const T& x)
void insert(iterator pos ,const T& x)
{
assert(pos>=_start);
//等于finish就是尾插
assert(pos<=_finish);
if(_finish==_end_of_storage)
{
//如果发生了扩容就要重新调整我们的pos指针的位置,不然就会发生迭代器失效的问题
size_t len=pos-_start;
reserve(capacity()==0? 4:capacity()*2);
//形参是实参的拷贝,并不会真正去改变我们外部的pos
//仅仅只能保证我们下面的pos使用是正常的
pos=_start+len;
}
//挪动数据
iterator end=_finish -1;
while(end>=pos)
{
*(end+1)=*end;
--end;
}
*pos=x;
++_finish;
}
2.随机位置擦除
随机位置擦除的话可以使用缩容来优化我们过大的空间,但是这是一种时间换空间的做法,一般不用做。可以将下面代码中的缩容那部分注释掉。
//stl规定erase返回删除位置的下一个位置迭代器
iterator erase(iterator pos)
{
assert(pos>=_start);
assert(pos<_finish);
iterator begin=pos+1;
//将当前位置不断挪动到前一个位置
while(begin<_finish)
{
*(begin-1)=*begin;
++begin;
}
--_finish;
if(size()<capacity()/2)
{
//缩容,以时间换空间。
_end_of_storage=_start+capacity()/2;
}
return pos;
}
3.清除函数clear
1)写法一:调用erase
void clear()
{
while(_finish!=_start)
{
erase(_start);
}
}
2)写法二:直接将_finish=_start
void clear()
{
_finish = _start;
}
测试代码
void myvector_test3()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
v.erase(v.begin());
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
测试代码(clear)
void myvector_test13()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
vector<int>::iterator it=v1.begin();
while(it!=v1.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
v1.clear();
vector<int>::iterator it2=v1.begin();
while(it2!=v1.end())
{
cout<<*it2<<" ";
it2++;
}
cout<<endl;
}
为什么要返回删除位置的下一个位置的迭代器?
观察下面几个代码的变化和问题
void myvector_test4()
{
//正常运行
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;
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
相比于上面 这里我们少push_back了5
//崩溃
void myvector_test5()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//要求删除所有的偶数
auto it=v.begin();
while(it!=v.end())
{
if(*it%2==0)
{
v.erase(it);
}
++it;
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
//4删不掉
void myvector_test6()
{
//正常运行
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(5);
//要求删除所有的偶数
auto it=v.begin();
while(it!=v.end())
{
if(*it%2==0)
{
v.erase(it);
}
++it;
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
这里的4我们没删掉
正确的使用方式是我们在erase的时候就要同步更新我们的pos
void myvector_test7()
{
//正常运行
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//要求删除所有的偶数
auto it=v.begin();
while(it!=v.end())
{
if(*it%2==0)
{
//同步更新我们的it
//如果删除了某个数据,it迭代器就不要继续往后走了
//因为后面的数据会移动上来,it迭代器当前指向位置并没有检查过
it=v.erase(it);
}
else
{
++it;
}
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
//结论:insert/erase pos位置,不要直接访问pos。
// 一定要更新,直接访问,可能会出现各种出乎意料的结果
//这就是pos所谓的迭代器失效。
//认为pos失效,不要访问。
//结果不同的底层实现可能不一样。
十一、迭代器的失效问题
1.迭代器失效就是当我们尾插数据的时候,如果发生了扩容,原来的地址空间可能就被转换到了一块更大的空间,所以我们迭代器的指针就失效了,就变成了一个野指针(程序会崩溃)。
2.或者是迭代器在insert之后,因为数据的挪动,pos指向的位置已经不再是原来的值了
//迭代器失效问题
void myvector_test2()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
//这里由于我们之前扩容的写法(在上面的push_back中看),是初始开辟四个,然后超出的话空间直接乘以两倍,所以我们在第五个数据插入的时候就会发生扩容
//在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
auto p=find(v.begin(),v.end(),3);
if(p!=v.end())
{
//在p位置插入数据以后,不要访问p,因为p可能失效
v.insert(p,30);
cout<<*p<<endl;
//因为上面的insert30的时候p的指针已经失效了,所以会报错
v.insert(p,40);
}
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
//如果上面的insert加了引用,下面这个代码就会报错。
//传值返回的都是数据的临时拷贝,这个拷贝具有常性,不能被修改,会报错
v.insert(v.begin(),1);
}
问题的解决
我们同样可以仿照erase中的写法,将我们insert函数中当前的扩容之后的对应位置的迭代器返回,然后及时同步迭代器,从而解决这个问题。
iterator insert(iterator pos ,const T& x)
{
assert(pos>=_start);
//等于finish就是尾插
assert(pos<=_finish);
if(_finish==_end_of_storage)
{
//如果发生了扩容就要重新调整我们的pos指针的位置,不然就会发生迭代器失效的问题
size_t len=pos-_start;
reserve(capacity()==0? 4:capacity()*2);
//形参是实参的拷贝,并不会真正去改变pos
pos=_start+len;
}
//挪动数据
iterator end=_finish -1;
while(end>=pos)
{
*(end+1)=*end;
--end;
}
*pos=x;
++_finish;
return pos;
}
测试代码
//迭代器失效问题
void myvector_test12()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
//在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
auto p=find(v.begin(),v.end(),3);
if(p!=v.end())
{
//在p位置插入数据以后,及时同步指针
p=v.insert(p,30);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
p=v.insert(p,40);
}
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
}
但其实这个迭代器失效问题在不同的编译器和平台下都是不同的。因为STL仅仅是一个规范,并没有将具体的代码写死。比方说老师要叫你上网课,你可以在图书馆上网课,可以在寝室上网课,也可以在家里上网课。所以STL同理,在不同的平台下实现是不同的,所以同一个程序在不同的平台下会有不同的表现。
比方说VS下面就是用PJ版本的STL,g++下使用的是SGI版本的STL。
十二、vector的深拷贝和浅拷贝
传统写法:
写法一:
//传统写法
vector(const vector<T>&v)
{
_start=new T[v.size()];//
memcpy(_start,v._start,sizeof(T)*v.size());
_finish=_start+v.size();
_end_of_storage=_start+v.size();
}
写法二:
vector(const vector<T>& v)
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(v.capacity());
for(const auto& e :v)
{
push_back(e);
}
}
现代写法:
v1=v2默认的是浅拷贝,我们需要转换成深拷贝
写法一:
等于赋值
vector<T>&operator =(vector<T> v)
{
swap(v);
return *this;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._endOfStorage);
}
拷贝构造
//v2(v1)
vector(const vector<T>& v)
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
vector<T> tmp (v.begin(),v.end());
swap(tmp);
}
写法二:
//现代写法
//可以在模板里面再次嵌套模板
template<class InputIterator>
vector(InputIterator first,InputIterator last)
: _start(nullptr)
,_finish(nullptr)
, _end_of_storage(nullptr)
{
while(first!=last)
{
push_back(*first);
++first;
}
}
//v2(v1)
vector(const vector<T>& v)
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
vector<T> tmp (v.begin(),v.end());
}
测试代码:
void myvector_test14()
{
//对于内置类型完整值拷贝,也就是浅拷贝
//1.同一个空间会被析构两次
//2.一个对象的修改会影响两个对象
//面对自定义类型,就会调用对应的拷贝构造函数
//深拷贝就是开辟一个与要拷贝的对象一样大的空间
//然后逐个元素拷贝
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int> v1=v;
cout<<"v"<<" ";
for(auto e:v)
{
cout<<e<<" ";
}
cout<<endl;
cout<<"v1"<<" ";
for(auto e:v1)
{
cout<<e<<" ";
}
cout<<endl;
v[2]*=2;
cout<<"v"<<" ";
for(auto e:v)
{
cout<<e<<" ";
}
cout<<endl;
cout<<"v1"<<" ";
for(auto e:v1)
{
cout<<e<<" ";
}
cout<<endl;
}
上面传入迭代器首尾位置的拷贝构造其实也可以拷贝string
void myvector_test15()
{
string s("hello world");
vector<int> v(s.begin(),s.end());
for(auto e:v)
{
cout<<(char)e<<" ";
}
cout<<endl;
}
测试调用=进行拷贝赋值
void myvector_test16()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
vector<int> v2;
v2=v;
for(auto e:v2)
{
cout<<e<<" ";
}
cout<<endl;
}
潜在的匹配问题
void myvector_test17()
{
int i=0;
//在c++中内置类型也有构造函数
int j=int();
cout<<j<<endl;
int k=int (10);
cout<<k<<endl;
vector<int> v1(10);
for(auto e:v1)
{
cout<<e<<" ";
}
cout<<endl;
//非法的间接寻址
//会报错
i=1;
//int int就出错了
//因为编译器的匹配的时候会去寻找最匹配的那一个
//所以这里匹配上了使用模板的那一个
//但是我们的模板中的Inputiterator此时没有被解析成迭代器指针,反而别解析成了int
//对int进行解引用,就会报错
// vector<int> v2(10,i);
// for(auto e:v2)
// {
// cout<<e<<" ";
// }
// cout<<endl;
//不会报错
//第一个是int,第二个是char
vector<char> v3(10,'a');
for(auto e:v3)
{
cout<<e<<" ";
}
cout<<endl;
}
上面中间那个报错的就是因为匹配了这个
解决方案
官方的STL直接给了好几个不同的构造函数
所以我们可以写一个新的构造函数让它能够匹配上
我们将我们之前的这个函数修改一下
改成这个样子,让它能够匹配上
vector(int n, const T& val = T())
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
for (size_t i = 0; i < n; ++i)
{
push_back(val);
}
}
对多维vector的拷贝问题
下面的Solution中是我们之前写过的杨辉三角的代码,也就是需要拷贝一个二维的vector的代码,但是,但我们执行了下面的代码之后,发现程序会崩溃,这是为什么呢?
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv;
vv.resize(numRows);
for (size_t i = 0; i < vv.size(); ++i)
{
vv[i].resize(i + 1, 0);
vv[i].front() = vv[i].back() = 1;
}
for (size_t i = 0; i < vv.size(); ++i)
{
for (size_t j = 0; j < vv[i].size(); ++j)
{
if (vv[i][j] == 0)
{
vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
}
}
}
for (size_t i = 0; i < vv.size(); ++i)
{
for (size_t j = 0; j < vv[i].size(); ++j)
{
cout << vv[i][j] << " ";
}
cout << endl;
}
//vector<vector<int>> ret = vv;
return vv;
}
};
void test_vector11()
{
vector<vector<int>> ret = Solution().generate(5);
}
从下图中我们可以看出,虽然我们的vector<vector<int>>是一模一样地拷贝了一份,但是其中的每一个vector<int>中的数据所指向的都是同一片空间,所以在析构函数进行的时候,会发生两次析构,从而导致崩溃。
解决方案
传统形式
对于我们之前使用传统形式的拷贝的方式,我们是因为使用了memcpy才导致我们的两个二维容器中的一维容器指向了同一片空间,我们只需要景memcpy的拷贝方式改成下面的一个个逐个拷贝就可以了。
//v2(v1)
vector(const vector<T>& v)
{
_start = new T[v.size()]; // v.capacity()也可以
//memcpy(_start, v._start, sizeof(T)*v.size());
for (size_t i = 0; i < v.size(); ++i)
{
_start[i] = v._start[i];
}
_finish = _start + v.size();
_end_of_storage = _start + v.size();
}
现代形式
我们注意到现代形式的写法中是用push_back拷贝的
push_back复用了insert
insert中调用了reserve进行我们上面的扩容操作,
修改我们的reserve的代码
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
//memcpy(tmp, _start, sizeof(T)*sz);
for (size_t i = 0; i < sz; ++i)
{
//不要在用memcpy,而是一个元素一个元素地拷贝
tmp[i] = _start[i];
}
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
成功实现拷贝
十三、主程序代码汇总
#ifndef VECTORTEST_MYVECTOR_H
#define VECTORTEST_MYVECTOR_H
#pragma once
#include <stdio.h>
#include <assert.h>
namespace zhuyuan
{
template<class T>
class vector
{
public:
typedef T* iterator;
const typedef T* const_iterator;
iterator begin()
{
return _start;
}
const iterator begin() const
{
return _start;
}
iterator end()
{
return _finish;
}
const iterator end() const
{
return _finish;
}
vector()
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
}
~vector()
{
delete[] _start;
_start=_finish=_end_of_storage= nullptr;
}
size_t capacity() const
{
return _end_of_storage-_start;
}
size_t size() const
{
return _finish-_start;
}
// vector<string> v;
// 如果下面的这个push_back不加const,就会报错,因为拷贝的这个字符串具有隐式类型转换
// 期间会生成一个中间的临时变量,而这个临时变量具有常性。如果不加const会发生权限的扩大。
// v.push_back("xxxx")
vector(size_t n, const T& value = T())
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(n);
while (n--)
{
push_back(value);
}
}
vector(iterator first,iterator last)
:_start(nullptr)
,_finish(nullptr)
,_end_of_storage(nullptr)
{
reserve(last-first+1);
iterator it=begin();
for(int i=0;i<last-first;i++)
{
*it=*(first+i);
it++;
}
_finish=_start+(last-first);
}
vector(const vector<T>& v)
: _start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reserve(v.capacity());
iterator it = begin();
const_iterator vit = v.begin();
while (vit != v.end())
{
*it++ = *vit++;
}
_finish = it;
}
vector<T>&operator =(vector<T> v)
{
swap(v);
return *this;
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._endOfStorage);
}
//开辟n个空间
void reserve(size_t n)
{
if(n>capacity())
{
size_t sz=size();
T*tmp=new T[n];
if(_start)
{
memcpy(tmp,_start,sizeof(T)*size());
delete[] _start;
}
_start=tmp;
_finish=_start+sz;
//由于上面的过程中我们将原先的_start给销毁了,新的_start变成了tmp
//所以其size可能会发生变化,
// _finish=_start+size();
_end_of_storage=_start+n;
}
}
//resize第一个参数是要调整到的大小,第二个参数是如果调整出来的大小大于了原来的数据用什么值填充
void resize(size_t n,const T&value=T())
{
//1.如果n小于当前的size,则数据个数缩小到n
if(n<=size())
{
_finish=_start+n;
return;
}
//2.空间不够则增容
if(n>capacity())
{
reserve(n);
}
//3.将size扩大到n
iterator it=_finish;
_finish=_start+n;
while(it!=_finish)
{
*it=value;
++it;
}
}
const T&operator [](size_t pos) const
{
assert(pos<size());
return _start[pos];
}
T&operator [](size_t pos)
{
assert(pos<size());
return _start[pos];
}
//使用泛型,输入的是T类型
void push_back(const T&x)
{
if(_finish==_end_of_storage)
{
reserve(capacity()==0?4 :capacity()*2);
}
//finish是最后一个数据的下一个位置
*_finish=x;
++_finish;
}
void pop_back()
{
assert(_finish>_start);
--_finish;
}
// void insert(iterator &pos ,const T& x)
iterator insert(iterator pos ,const T& x)
{
assert(pos>=_start);
//等于finish就是尾插
assert(pos<=_finish);
if(_finish==_end_of_storage)
{
//如果发生了扩容就要重新调整我们的pos指针的位置,不然就会发生迭代器失效的问题
size_t len=pos-_start;
reserve(capacity()==0? 4:capacity()*2);
//形参是实参的拷贝,并不会真正去改变pos
pos=_start+len;
}
//挪动数据
iterator end=_finish -1;
while(end>=pos)
{
*(end+1)=*end;
--end;
}
*pos=x;
++_finish;
return pos;
}
//stl规定erase返回删除位置的下一个位置迭代器
iterator erase(iterator pos)
{
assert(pos>=_start);
assert(pos<_finish);
iterator begin=pos+1;
//将当前位置不断挪动到前一个位置
while(begin<_finish)
{
*(begin-1)=*begin;
++begin;
}
--_finish;
if(size()<capacity()/2)
{
//缩容,以时间换空间。
_end_of_storage=_start+capacity()/2;
}
return pos;
}
private:
iterator _start;
//finish是最后一个数据的下一个位置
iterator _finish;
//_end_of_storage是我们整个vector的容量大小
iterator _end_of_storage;
};
}
#endif //VECTORTEST_MYVECTOR_H
十四、测试程序代码汇总
调用测试程序
using namespace std;
#include "myvector.h"
int main()
{
try
{
zhuyuan::myvector_test1();
}
catch(std::exception&e)
{
std::cout<<e.what()<<std::endl;
}
}
测试程序
void Func(const vector<int>&v)
{
vector<int>::const_iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
}
void myvector_test1()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
cout<<endl;
//有了迭代器就支持范围for,也就是调用我们的v.begin(),v.end()来执行相关的操作
//const的话就走const的迭代器,
for(auto e:v)
{
cout<<e<<" ";
}
v.pop_back();
cout<<endl;
Func(v);
}
//迭代器失效问题
void myvector_test2()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
//在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
auto p=find(v.begin(),v.end(),3);
if(p!=v.end())
{
//在p位置插入数据以后,不要访问p,因为p可能失效
v.insert(p,30);
cout<<*p<<endl;
v.insert(p,40);
}
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
//如果上面的insert加了引用,下面这个代码就会报错。
//传值返回的都是数据的临时拷贝,这个拷贝具有常性,不能被修改,会报错
v.insert(v.begin(),1);
}
void myvector_test3()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
v.erase(v.begin());
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
void myvector_test4()
{
//正常运行
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;
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
//崩溃
void myvector_test5()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
//要求删除所有的偶数
auto it=v.begin();
while(it!=v.end())
{
cout<<"it"<<*it<<endl;
// cout<<*it<<endl;
if(*it%2==0)
{
cout<<"end()"<<v.end()-v.begin()<<endl;
v.erase(it);
}
++it;
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
//4删不掉
void myvector_test6()
{
//正常运行
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(5);
//要求删除所有的偶数
auto it=v.begin();
while(it!=v.end())
{
if(*it%2==0)
{
v.erase(it);
}
++it;
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
void myvector_test7()
{
//正常运行
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(4);
v.push_back(3);
v.push_back(4);
v.push_back(5);
//要求删除所有的偶数
auto it=v.begin();
while(it!=v.end())
{
if(*it%2==0)
{
it=v.erase(it);
}
else
{
++it;
}
}
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
}
//结论:insert/erase pos位置,不要直接访问pos。
// 一定要更新,直接访问,可能会出现各种出乎意料的结果
//这就是pos所谓的迭代器失效。
//认为pos失效,不要访问。
//结果不同的底层实现可能不一样。
void myvector_test8()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
vector<int> v2(v1);
vector<int>::iterator it=v2.begin();
while(it!=v2.end())
{
cout<<*it<<" ";
it++;
}
cout<<endl;
}
void myvector_test9()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
vector<int> v2(v1.begin(),v1.end());
cout<<v2[1]<<endl;
}
void myvector_test10()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
vector<int> v2=v1;
vector<int>::iterator it1=v1.begin();
while(it1!=v1.end())
{
cout<<*it1<<" ";
it1++;
}
cout<<endl;
vector<int>::iterator it2=v2.begin();
while(it2!=v2.end())
{
cout<<*it2<<" ";
it2++;
}
cout<<endl;
}
void myvector_test11()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
vector<int>::iterator it1=v1.begin();
while(it1!=v1.end())
{
cout<<*it1<<" ";
it1++;
}
cout<<endl;
vector<int>v2=v1;
v1.resize(7,5);
vector<int>::iterator it2=v1.begin();
while(it2!=v1.end())
{
cout<<*it2<<" ";
it2++;
}
cout<<endl;
}
//迭代器失效问题
void myvector_test12()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
// v.push_back(5);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
//在vector发生扩容的时候,我们的迭代器的指针就失效了,就会发生迭代器失效的问题
auto p=find(v.begin(),v.end(),3);
if(p!=v.end())
{
//在p位置插入数据以后,及时同步指针
p=v.insert(p,30);
for(size_t i=0;i<v.size();++i)
{
cout<<v[i]<<" ";
}
cout<<endl;
p=v.insert(p,40);
}
vector<int>::iterator it=v.begin();
while(it!=v.end())
{
cout<<*it<<" ";
++it;
}
}
十五、vector原码
可以对照原码查看我们上面的模拟实现代码
/*
*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
/* NOTE: This is an internal header file, included by other STL headers.
* You should not attempt to use it directly.
*/
#ifndef __SGI_STL_INTERNAL_VECTOR_H
#define __SGI_STL_INTERNAL_VECTOR_H
__STL_BEGIN_NAMESPACE
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma set woff 1174
#endif
template <class T, class Alloc = alloc>
class vector {
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator<const_iterator> const_reverse_iterator;
typedef reverse_iterator<iterator> reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_iterator<const_iterator, value_type, const_reference,
difference_type> const_reverse_iterator;
typedef reverse_iterator<iterator, value_type, reference, difference_type>
reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
protected:
typedef simple_alloc<value_type, Alloc> data_allocator;
iterator start;
iterator finish;
iterator end_of_storage;
void insert_aux(iterator position, const T& x);
void deallocate() {
if (start) data_allocator::deallocate(start, end_of_storage - start);
}
void fill_initialize(size_type n, const T& value) {
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
public:
iterator begin() { return start; }
const_iterator begin() const { return start; }
iterator end() { return finish; }
const_iterator end() const { return finish; }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
size_type size() const { return size_type(end() - begin()); }
size_type max_size() const { return size_type(-1) / sizeof(T); }
size_type capacity() const { return size_type(end_of_storage - begin()); }
bool empty() const { return begin() == end(); }
reference operator[](size_type n) { return *(begin() + n); }
const_reference operator[](size_type n) const { return *(begin() + n); }
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_initialize(n, value); }
vector(int n, const T& value) { fill_initialize(n, value); }
vector(long n, const T& value) { fill_initialize(n, value); }
explicit vector(size_type n) { fill_initialize(n, T()); }
vector(const vector<T, Alloc>& x) {
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
vector(InputIterator first, InputIterator last) :
start(0), finish(0), end_of_storage(0)
{
range_initialize(first, last, iterator_category(first));
}
#else /* __STL_MEMBER_TEMPLATES */
vector(const_iterator first, const_iterator last) {
size_type n = 0;
distance(first, last, n);
start = allocate_and_copy(n, first, last);
finish = start + n;
end_of_storage = finish;
}
#endif /* __STL_MEMBER_TEMPLATES */
~vector() {
destroy(start, finish);
deallocate();
}
vector<T, Alloc>& operator=(const vector<T, Alloc>& x);
void reserve(size_type n) {
if (capacity() < n) {
const size_type old_size = size();
iterator tmp = allocate_and_copy(n, start, finish);
destroy(start, finish);
deallocate();
start = tmp;
finish = tmp + old_size;
end_of_storage = start + n;
}
}
reference front() { return *begin(); }
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); }
const_reference back() const { return *(end() - 1); }
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
void swap(vector<T, Alloc>& x) {
__STD::swap(start, x.start);
__STD::swap(finish, x.finish);
__STD::swap(end_of_storage, x.end_of_storage);
}
iterator insert(iterator position, const T& x) {
size_type n = position - begin();
if (finish != end_of_storage && position == end()) {
construct(finish, x);
++finish;
}
else
insert_aux(position, x);
return begin() + n;
}
iterator insert(iterator position) { return insert(position, T()); }
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void insert(iterator position, InputIterator first, InputIterator last) {
range_insert(position, first, last, iterator_category(first));
}
#else /* __STL_MEMBER_TEMPLATES */
void insert(iterator position,
const_iterator first, const_iterator last);
#endif /* __STL_MEMBER_TEMPLATES */
void insert (iterator pos, size_type n, const T& x);
void insert (iterator pos, int n, const T& x) {
insert(pos, (size_type) n, x);
}
void insert (iterator pos, long n, const T& x) {
insert(pos, (size_type) n, x);
}
void pop_back() {
--finish;
destroy(finish);
}
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
iterator erase(iterator first, iterator last) {
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
return first;
}
void resize(size_type new_size, const T& x) {
if (new_size < size())
erase(begin() + new_size, end());
else
insert(end(), new_size - size(), x);
}
void resize(size_type new_size) { resize(new_size, T()); }
void clear() { erase(begin(), end()); }
protected:
iterator allocate_and_fill(size_type n, const T& x) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
#ifdef __STL_MEMBER_TEMPLATES
template <class ForwardIterator>
iterator allocate_and_copy(size_type n,
ForwardIterator first, ForwardIterator last) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_copy(first, last, result);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
#else /* __STL_MEMBER_TEMPLATES */
iterator allocate_and_copy(size_type n,
const_iterator first, const_iterator last) {
iterator result = data_allocator::allocate(n);
__STL_TRY {
uninitialized_copy(first, last, result);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
#endif /* __STL_MEMBER_TEMPLATES */
#ifdef __STL_MEMBER_TEMPLATES
template <class InputIterator>
void range_initialize(InputIterator first, InputIterator last,
input_iterator_tag) {
for ( ; first != last; ++first)
push_back(*first);
}
// This function is only called by the constructor. We have to worry
// about resource leaks, but not about maintaining invariants.
template <class ForwardIterator>
void range_initialize(ForwardIterator first, ForwardIterator last,
forward_iterator_tag) {
size_type n = 0;
distance(first, last, n);
start = allocate_and_copy(n, first, last);
finish = start + n;
end_of_storage = finish;
}
template <class InputIterator>
void range_insert(iterator pos,
InputIterator first, InputIterator last,
input_iterator_tag);
template <class ForwardIterator>
void range_insert(iterator pos,
ForwardIterator first, ForwardIterator last,
forward_iterator_tag);
#endif /* __STL_MEMBER_TEMPLATES */
};
template <class T, class Alloc>
inline bool operator==(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
}
template <class T, class Alloc>
inline bool operator<(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}
#ifdef __STL_FUNCTION_TMPL_PARTIAL_ORDER
template <class T, class Alloc>
inline void swap(vector<T, Alloc>& x, vector<T, Alloc>& y) {
x.swap(y);
}
#endif /* __STL_FUNCTION_TMPL_PARTIAL_ORDER */
template <class T, class Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator=(const vector<T, Alloc>& x) {
if (&x != this) {
if (x.size() > capacity()) {
iterator tmp = allocate_and_copy(x.end() - x.begin(),
x.begin(), x.end());
destroy(start, finish);
deallocate();
start = tmp;
end_of_storage = start + (x.end() - x.begin());
}
else if (size() >= x.size()) {
iterator i = copy(x.begin(), x.end(), begin());
destroy(i, finish);
}
else {
copy(x.begin(), x.begin() + size(), start);
uninitialized_copy(x.begin() + size(), x.end(), finish);
}
finish = start + x.size();
}
return *this;
}
template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
if (finish != end_of_storage) {
construct(finish, *(finish - 1));
++finish;
T x_copy = x;
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
}
else {
const size_type old_size = size();
const size_type len = old_size != 0 ? 2 * old_size : 1;
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
construct(new_finish, x);
++new_finish;
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(begin(), end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position, size_type n, const T& x) {
if (n != 0) {
if (size_type(end_of_storage - finish) >= n) {
T x_copy = x;
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n) {
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
fill(position, position + n, x_copy);
}
else {
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
}
else {
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
new_finish = uninitialized_fill_n(new_finish, n, x);
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
#ifdef __STL_MEMBER_TEMPLATES
template <class T, class Alloc> template <class InputIterator>
void vector<T, Alloc>::range_insert(iterator pos,
InputIterator first, InputIterator last,
input_iterator_tag) {
for ( ; first != last; ++first) {
pos = insert(pos, *first);
++pos;
}
}
template <class T, class Alloc> template <class ForwardIterator>
void vector<T, Alloc>::range_insert(iterator position,
ForwardIterator first,
ForwardIterator last,
forward_iterator_tag) {
if (first != last) {
size_type n = 0;
distance(first, last, n);
if (size_type(end_of_storage - finish) >= n) {
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n) {
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
copy(first, last, position);
}
else {
ForwardIterator mid = first;
advance(mid, elems_after);
uninitialized_copy(mid, last, finish);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
copy(first, mid, position);
}
}
else {
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
new_finish = uninitialized_copy(first, last, new_finish);
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
#else /* __STL_MEMBER_TEMPLATES */
template <class T, class Alloc>
void vector<T, Alloc>::insert(iterator position,
const_iterator first,
const_iterator last) {
if (first != last) {
size_type n = 0;
distance(first, last, n);
if (size_type(end_of_storage - finish) >= n) {
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n) {
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish);
copy(first, last, position);
}
else {
uninitialized_copy(first + elems_after, last, finish);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
copy(first, first + elems_after, position);
}
}
else {
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY {
new_finish = uninitialized_copy(start, position, new_start);
new_finish = uninitialized_copy(first, last, new_finish);
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch(...) {
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
#endif /* __STL_MEMBER_TEMPLATES */
#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
#pragma reset woff 1174
#endif
__STL_END_NAMESPACE
#endif /* __SGI_STL_INTERNAL_VECTOR_H */
// Local Variables:
// mode:C++
// End: