C++vector插入时的内存分配

C++vector插入时的内存分配

今天在看侯建的《STL源码剖析》时看到插入操作时发现多了一个拷贝构造的时候,有点疑惑,于是自己做了一个实验,对vector的push_back()操作时的内存分配进行了仔细的了解。


vector的push_back()操作原理

简单来说,push_back()就是往vector之后插入元素,这也是vector跟array最大的区别,array只能是固定大小,而有了vector之后,就可以动态扩大其容量了。

这里解释一下vector插入时的一些基本原理。

vector中元素与待插入元素绝对不是同一个对象

因为vector使用的alloc(用于分配内存)一直是从堆或者内存池(内存池应该是也属于堆)中获取内存,所以vector中所有的元素肯定不是位于栈上,就是我有一个int a=3,那么a肯定是位于栈上的,但是vector<int>b;b.push_back(a);之后,b[0]虽然值等于a,但是和a已经不是一个对象了,vector会在堆上给其重新分配内存。

vector的capacity属性

vector的capacity属性可由vector<int>b;...;b.capacity();获得,代表了当前vector分配的大小;也就是当前vector中所能容纳的元素的个数。vector在插入时,如果:插入数量+已有数量<=vector.capacity()就直接插入,而插入数量+已有数量>vector.capacity()时就需要申请更多的内存了。那么究竟是如何申请内存呢?

实验

我们会依次尝试向vector中插入元素。查看vector究竟是如何分配内存的。

测试代码块

#include<iostream>                                                          
#include<vector>
using namespace std;

class A{ 
    private:
    static int a; //标识A的数量   
    public:
    A(){ 
        a++;
        cout<<a<<"  "<<this<<endl;//显示新构造的A的对象的地址
    }    
    A(const A &b){
        a++;
        cout<<a<<" "<<this<<endl;//显示由拷贝构造函数构造的A的对象的地址
    }    
    ~A(){
        cout<<this<<" has been destoried!\n";//显示被析构掉的对象的地址
    }    
};       
int A::a=0;
int main(){
vector<A>re;
    A s1;
    re.push_back(s1);
    cout<<"A capacity is :"<<re.capacity()<<" "<<&re[0]<<endl;//输出re分配的大小和首元素的地址
    cout<<endl;
    A s2;
    re.push_back(s2);
    cout<<"A capacity is :"<<re.capacity()<<"  "<<&re[0]<<endl;
    cout<<endl;
    A s3;
    re.push_back(s3);
    cout<<"A capacity is :"<<re.capacity()<<" "<<&re[0]<<endl;
    cout<<endl;
    A s4;                                                                   
    re.push_back(s4);
    cout<<"A capacity is :"<<re.capacity()<<" "<<&re[0]<<endl;
    cout<<endl;
    A s5;
    re.push_back(s5);
    cout<<"A capacity is :"<<re.capacity()<<" "<<&re[0]<<endl;
    cout<<endl;
    return 0;
}

运行结果

实验分析

构造S1调用了普通构造函数,但是把他放入vector是调用的却是拷贝构造函数,而且拷贝构造函数构造出来的对象就是vector[0];
构造S2是也是调用了普通构造函数,但却调用两次拷贝构造函数,和依次析构函数,显然可以看到析构掉的是之前的vector[0],而两个拷贝构造其中一个就是vector[0],那么另一个显然是vector1,就是新插入的元素。可以看出,当插入数量+已有数量>vector.capacity()时,系统会现将原有的vector中所有元素拷贝一份到新的地址中,然后将之前的vector中的元素全部析构掉。其实从《STL源码分析》中可以看到,此时vector中的start,finish和end_of_storage三个指针也同步更新了。
以此类推,我在最后依次插入S5的时候,因为5>re.capacity()=4,所以程序调用拷贝构造函数重新构造了之前的四个对象,当然刚开始还是构造了要push_back()进去的S5。最后再将之前的vector中的元素4个元素全部析构掉。

结论

vector在插入元素的时候,首先调用拷贝构造函数在堆中申请内存构造对象,如果插入对象数量没有超过vector的capacity,就直接插入;若超过了就在调用拷贝构造函数将之前vector中所有的元素都重新构造一边放入新的内存中,然后将之前vector中所有的元素全部析构掉,并释放内存。


  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值