vector 是一段连续的线性内存空间。
Vector类维护3 个迭代器(三个类型指针)来表示:
start,finish,end_of_storage
其中,start 指向的是 vector 容器对象的起始字节位置;last 指向当前最后一个元素的末尾字节;end_of_storage指向整个 vector 容器所占用内存空间的末尾字节。
start 和 finish 可以用来表示 vector 容器中目前已被使用的内存空间;
finish和 end_of_storage 可以用来表示 vector 容器目前空闲的内存空间;
start 和 end_of_storage可以用表示 vector 容器的容量。
对于空的 vector 容器,由于没有任何元素的空间分配,因此 start,finsh 和 end_of_storage 均为 null。
当我们使用vector::iterator it;时,it就是TYPE* 类型指针,上述三个迭代器也是如此。
通过灵活运用这 3 个迭代器,vector 容器可以轻松的实现诸如首尾标识、大小、容器、空容器判断等几乎所有的功能,比如:
template <class _Ty, class _Alloc = allocator<_Ty>>
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重载了[ ],可以方便存取值。
需要注意的是,当我们访问尾元素时,迭代器可不是*.end(),而是*.end()-1。
vector扩容机制
另外需要指明的是,当 vector 的大小和容量相等(size==capacity)也就是满载时(end_of_storage不够时),如果再向其添加元素,那么 vector 就需要扩容。vector 容器扩容的过程需要经历以下 3 步:
完全弃用现有的内存空间,重新申请更大的内存空间;(重新配置)
将旧内存空间中的数据,按原有顺序移动到新的内存空间中;(元素搬移)
最后将旧的内存空间释放。( 这也就解释了,为什么 vector 容器在进行扩容后,与其相关的指针、引用以及迭代器可能会失效的原因。(释放原内存))
由此可见,vector 扩容是非常耗时的。为了降低再次分配内存空间时的成本,每次扩容时 vector 都会申请比用户需求量更多的内存空间(这也就是 vector 容量的由来,即 capacity>=size),以便后期使用。
vector 容器扩容时,不同的编译器申请更多内存空间的量是不同的。以 VS 为例,它会扩容现有容器容量的 50%。(一般都是扩容两倍)
源码:
template<class T1, class T2>
inline void construct(T1* p, const T2& value)
{
new(p) T1(value); //placement new, 调用T1::T1(value);
}
template <class T, class Alloc = alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x)
{
//还有备用空间
if (finish != end_of_storage)
{
//在备用空间起始处构造一个元素,并以vector最后一个值为其初值
construct(finish, *(finish - 1));
//调整水位
++finish;
//拷贝一个元素
T copy_x = x;
//把vector插入位置position之后的元素往后移一位
copy_backward(position, finish - 2, finish - 1);
//给position指向的地方赋值,赋值内容为前面拷贝的元素
*position = copy_x;
}
//已无备用空间
else
{
const size_type old_size = size();
//如果原来的vector为空,则申请一个元素的空间,否则申请可以容纳原来2倍元素的空间
const size_type len = old_size == 0 ? 1 : 2 * old_size;
//全局函数,申请空间
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
try
{
//将原来vector的position之前的内容拷贝到新的vector前面
new_finish = uninitialized_copy(start, position, new_start);
//调用构造函数为新插入的元素赋值
construct(new_finish, x);
//调整水位
++new_finish;
//将原来vector的postion之后的内容拷贝到新的vector后面
new_finish = uninitialized_copy(position, finish, new_finish);
}
catch (...)
{
//析构
destroy(new_start, new_finish);
//释放刚刚申请的内存
data_allocator::deallocate(new_start, len);
throw;
}
//析构原vecotr
destroy(begin(), end());
//释放原vector的空间
deallocate();
//调整迭代器指向新的vector
start = new_start;
finish = new_finish;
end_of_storage = new_start +len;
}
}
void push_back(const T& x)
{
if(finish!=end_of_storage)//还有备用空间
{
construct(finish,x);
++finish;
}
else//以无备用空间
{
insert_aux(finish, x);
}
}