vector扩容

来源:互联网 发布:linux c一站式编程pdf 编辑:程序博客网 时间:2024/05/16 14:18

vector向量容器相当于一个动态的数组,当向向量容器中不断加入元素,若超过容器本身的大小限制,vector会自动拓展大小,在这过程中涉及到内存的分配和回收。在veector中有size()和capacity()函数。size()函数是指返回当前容器中的元素个数,对应的resize(size_type)会在容器尾添加或删除一些元素,来调整容器中实际的内容,使容器达到指定的大小。capacity()指最少要多少元素才会使其容量重新分配,对应的reserve(size_type new_size)会置这个capacity值,使它不小于所指定的new_size。VS2012是以1.5倍扩容,gcc是以两倍扩容

int main(){    vector<int> vec;    for(int i=0;i<50;++i)    {           cout<<vec.size()<<" "<<vec.capacity()<<endl;vec.push_back(i);    }}VS2012下:

这里写图片描述

gcc下:
这里写图片描述

可以看出在VS2012下,vector一次增长1.5倍
在gcc下,vector一次增长2倍(STL中的vector一次增长2倍)

vector大小拓展过程?
1)为需要的新容量分配足够的内存;
2)将元素从原来的内存拷贝到新内存中;
3)销毁原来内存中的元素;
4)归还原来的内存。

vector为什么要成倍的扩容而不是一次增加一个固定大小的容量呢?
成倍扩容,vector中push_back操作的时间复杂度为O(1)。
一次增加一个固定大小的容量,vector中push_back操作的时间复杂度为O(n)。对比就可以发现,采用成倍方式方式扩容,时间复杂度更小。

vector为什么是以两倍的方式扩容而不是三倍四倍,或者其他方式呢?
为了防止申请内存浪费,较多使用2倍和1.5倍,而1.5倍的增长方式可以更好的实现对内存的重复利用。减小堆空间浪费

如何减小vector初始内存分配频繁 ?
调用reserve(),reserve只开辟内存,resize()不仅开辟内存,还增加了元素个数。
源码如下:

template<class T,class Alloc = alloc>class vector{public:    //vector的嵌套型别定义    typedef T value_type;    typedef value_type * pointer;    typedef value_type * iterator;    typedef value_type & reference;    typedef size_t size_type;    typedef ptrdiff_t difference_type;protected:    //以下,simple_alloc是SGI STL的空间配置器    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;}     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()cosnt {return begin()==end();}    reference operator[](size_type n) { retutrn *begin() + n;}    vector():start(0),finish(0),end_of_storage(0) {}    //构造函数,允许指定vector大小n和初值value    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()    {        destroy(start,finish); //全局函数  可看上一篇空间配置器        deallocate();          //这是vector的一个member function    }    reference front() {return *begin();}     //第一个元素    reference back() {return *(end() - 1);}  //最后一个元素    /*将新元素插入于vector尾端时,该函数首先检查是否还有备用空间,如果有就直接    在备用空间上构造元素,并调整迭代器finish,使vector变大,如果没有备用空间了,    就扩充空间(重新配置,移动数据,释放原空间)*/    void push_back(const T& x) //将元素插入至最尾端    {        if(finish != end_of_storage)//还有备用空间        {            construct(finish,x);  //全局函数  可看上一篇空间配置器            ++finish;             //调整水位高度        }        else                      //已无备用空间        {            insert_aux(end(),x);          }    }    void 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            {                //将原来vector的内容拷贝到新vector                new_finish = uninitialized_copy(start,position,new_start);                //为新元素设定初值x                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;            }    }    void pop_back()  //将最尾端元素取出    {        --finish;  //将尾端标记往前移一格,表示已放弃尾端元素        destroy(finish);   //全局函数  可看上一篇空间配置器    }    //清除[first,last]中的所有元素    iterator erase(iterator first,iterator last)    {        iterator i = copy(last,finish,first);        destroy(i,finish);        finsh = finish - (last - first);        return first;    }    //清除某位置上的元素    iterator erase(iterator position)    {        if(position + 1 != end())            copy(position+1,finish,position);//后续元素往前移动        --finish;        destroy(finish);        return position;    }    void resize(size_type new_size,const T&x)    {        if(new_size < size())            erase(begin()+new_size,end());        else            inser(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,cosnt T&x)    {        iterator result = data_allocator::allocate(n); //表示配置n个元素空间        //会根据第一参数的型别特性,决定使用算法fill_n()或        //反复调用construct()来完成任务        uninitialized_fill_n(result,n,x);        return result;    }};
原创粉丝点击