- vector概述
- vector的迭代器
- vector的数据结构
- vector的构造与内存管理
- vector的元素操作
vector的数据安排以及操作方式与array非常相似,两者的唯一差别在于空间的运用的灵活性,array是静态空间,一旦配置了就不能改变,vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素
vector的迭代器vector维护的是一个连续线性空间,所以不论其元素型别为何,普通指针都可以作为vector的迭代器而满足所有必要条件,所以vector提供的是Random Access Iterators
templatevector的数据结构class vector { typedef T value_type; typedef value_type* iterator; };
vector所采用的数据结构非常简单:线性连续空间。它以两个迭代器start和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代器end_of_storage指向整块连续空间的尾端:
templateclass vector { protected: iterator start; iterator finish; iterator end_of_storage; };
运用start,finish,end_of_storage三个迭代器,便可轻易地提供首尾标示,大小,容量,空容器判断,注标([])运算子等功能
templatevector的构造与内存管理class vector { public: iterator begin() { return start;} iterator end() { return finish;} size_type size() const { return size_type(end()-begin()); } 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); } reference front() { return *begin(); } reference back() { return *(end()-1); } };
vector提供许多constructs,其中一个允许我们指定空间大小及初值:
//构造函数,允许指定vector大小n和初值value
vector(size_type n,const T& value)
{
fill_initialize(n,value);
}
//填充并予以初始化
void fill_initialize(size_type n,const T& value)
{
start =allocte_and_fill(n,value);
finish=start+n;
end_of_storage=finish;
}
//配置而后填充
iterator allocate_and_fill(size_type n,const T& x)
{
iterator result=data_allocator::allocate(n);
unititalized_fill_n(result,n,x);
return result;
}
当我们以push_back()将新元素插入到vector尾端时,该函数首先检查是否还有备用空间,如果有就直接在备用空间上构造元素,并调整迭代器finish,使vector变大,如果没有备用空间了,就扩充空间(重新配置,移动数据,释放空间)
void push_back(const T& x)
{
if(finish!=end_of_storage)
{
construct(finish,x);
++finish;
}
else
insert_aux(end(),x);
}
template
void vector::insert_aux(iterator position,const T& x)
{
if(finish!=end_of_storage)//还有备用空间
{
//在备用空间起始构造一个元素,并以vector最后一个元素值为其初值
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;
//以上配置原则:如果原大小为0,则配置1个元素大小
//如果原大小不为0,则配置原大小的两倍
//前半段用来放置原数据,后半段准备用来放置新数据
iterator new_start=data_allocator::allocate(len);
iterator new_finish=new_start;
try
{
new_finish=uninitialized_copy(start,position,new_start);
construct(new_finish,x);
++new_finish;
//将原vector的备用空间中的内容也忠实拷贝过来
new_finish=uninitialized_copy(position,finish,new_finish);
}
catch(...)
{
destroy(new_start,new_finish);
data_allocator::deallocate(new_start,len);
throw;
}
//析构并释放原vector
destroy(begin(),end());
deallocate();
//调整迭代器,指向新vector
start=new_start;
finish=new_finish;
end_of_storage=new_start+len;
}
}
所谓的动态增加大小,并不是在原空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间,因此,对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器都失效了
vector的元素操作//将尾端元素拿掉,并调整大小
void pop_back()
{
--finish;//将尾端标记前移一格,表示将放弃尾端元素
destroy(finish);
}
//清除[first,last)中的所有元素
iterator erase(iterator first,iterator last)
{
iterator i=copy(last,finish,first);
destroy(i,finish);
finish=finish-(last-first);
return first;
}
下面是vector::insert()实现内容:
//从position开始,插入n个元素,元素初值为x templatevoid vector ::insert(iterator position,size_type n,const T& x) { if(n!=0)//当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); finsih+=elems_after; fill(position,old_finish,x_copy); } } } else { //备用空间小于新增元素个数(那就必须配置额外的内存) //首先决定新长度:旧长度的两倍,或旧长度+新增元素个数 const size_type old_size=size(); const size_ype len=old_size+max(old_size,n); //以下配置新的vector空间 iterartor new_start=data_allocator::allocate(len); iterator new_finish=new_start; _STL_TRY { //以下首先将旧vector的插入点之前的元素复制到新空间 new_finish=uninitialized_copy(start,position,new_start); //以下再将新增元素填入新空间 new_finish=uninitialized_copy_n(new_finish,n,x); new_finish=uninitialized_copy(psition,finish,new_finish); } } #ifdef _STL_USE_EXCEPTIONS catch(...) { destroy(new_start,new_finish); data_allocator::deallocate(new_start,len); throw; } #endif destroy(start,finish); deallocate(); deallocate(); start=new_start; finsih=new_finish; end_of_storage=new_start+len; } } }



