目录
- 前言
- 发生扩容
- 扩容机制
- size()和capacity()
- reserve()和resize()
前言
前阵子面试的时候,被问到往vector中插入一个数据可能会发生什么?
我答:可能会扩容;
为啥vector支持变长?
我答:它实在堆上动态申请内存,因此有自己的一套扩容机制,可以操作内存大小;
它有size()和capacity()记录当前的有效元素个数和容量, 还有配套的resize()管理实际存放元素个数接口 和 reserve()管理容量接口;
下面我们详解;
发生扩容
vector作为STL的常用容器之一,其特性和数组类似,拥有一段连续的内存空间。vector申请的是一段连续的内存,**当插入新的元素内存不够时,通常会再重新申请更大的一块内存,将原来的元素拷贝过去,释放旧空间。**因为内存空间是连续的,所以在进行插入和删除操作时,会造成整体内存块的拷贝,时间复杂度为O(n)。
扩容机制
size()和capacity()
不同编译器在vector的扩容策略上显然不太一致,在vector的size()(当前容器所用的空间) 等于capacity()(当前容器总空间)时,再次插入一个元素就会发生扩容。
vs编译器每次是以1.5倍且向下取整的策略进行扩容,gcc编译器则是每次以2.0倍的策略进行扩容。(注意,初始size和capacity是0,在0的基础上第一次进行扩容的时候取第一次插入元素的个数!)
size()和capacity()是俩成员函数,vector中并没有直接存int size 和 capacity,存的其实是有效数据的始末地址和容量结尾地址
通过源码分析有三个指针:
start和finish和end_of_storage,他们三个指针用减法能算出来逻辑上的int size和int capacity数量;
reserve()和resize()
-
reserve()来改变capacity()容量的大小,是预留容器空间;
-
resize()改变size(),是有效存储元素个数;
通过源码分析:
reserve(int n)
void reserve(size_type __n){
if (__n > max_size()){
__throw_length_error(__N("vector::reserve"));
}
if (capacity() < __n){
_M_reallocate(__n);
}
}
调整capacity, 存在if判断,当n>当前capacity才有效,否则什么事都不发生;
resize(int n)
void resize(size_type __new_size){
if (__new_size > size()){
_M_default_append(__new_size - size());
}
else if (__new_size < size()){
_M_erase_at_end(this->_M_impl._M_start + __new_size);
}
}
调整size:
当size>=capacity时,capacity和size都扩容到size大小,多出来的有效元素补上缺省值(int为0);
当 size<capacity,释放多余的元素,size缩减到指定大小,capacity不变;