讨论标准模板库std::vector的容量/大小及其内存增量

首先解释一下容量/大小的区别:
  std::vector::capacity() : 指容器的能容纳多少个。
  std::vector::size() : 指容器当前已装多少个。
明白上面的意思思路就清晰多了。

 

这几天有同事用vector的时候遇到问题,说是当push_back以后,以前引用了vector的地址就不能访问。
造成以前引用的地址不能使用的原因估计大家都知道。
主要原因是vector有一个内存增量机制。


内增量机制是:为了满路容器的连续内存访问,当vector发现自己内存不够用,就需要重新申请内存,
然后复制旧的数据过去,删除旧的数据,重新指向新的数据地址。
当这个复制过程一结束的时候,以前引用了下标为0的vector内存地址就会不再是该数据地址了,
已被复制走的原有数据已删除成为野内存。
这时需要重去引用一次。

 

关于这个增量机制网上有多种说法,
  1说法:按原有尺寸的2倍增长,即:new_capacity = capacity_size * 2;
  2说法:按原有尺寸的50%增加,即:new_capacity = capacity_size / 2 + capacity_size;
  3说法:按数据尺寸倍数增长,即 sizeof(class) * 2;
  4说法:按字节来,即: (1024)/sizeof(class);


就此问题,我专门去看了看vector的原代码。得到的结果是:2说法正确。
这点可以从std::vector::_Insert_n(iterator, size_type, const _Ty&)的原代码中可以看出:

// 如果容量 < 大小 + 新数量增量
else if (_Capacity < size() + _Count)
{
  // 容量 = 容量 + 容量 / 2;
  _Capacity = max_size() - _Capacity / 2 < _Capacity ? 0 : _Capacity + _Capacity / 2; 
  // 容量 < 大小 + 新增数量
  if (_Capacity < size() + _Count)
    // 容量 = 大小 + 新增数量
    _Capacity = size() + _Count;
  // 申请新内存
  pointer _Newvec = this->_Alval.allocate(_Capacity);
  // 开始引用地址
  pointer _Ptr = _Newvec;
  // 复制与删除过程
  ......
}

 

那么如何解决我即想引用vector的地址又不需要经常去刷新该地址呢?
同时又解决掉vector的复制问题,也解决掉有些类的复制构造?
方法还是有的。
这里就有前面提到的容量/大小的因素了。
容量必然大于大小,是肯定的,即:capacity >= size;

 

方法1:
  创建std::vector容器,并调用std::vector::reserve(int n);
  告诉vector的直接增加n个数据并分配内存,
  这样的话push_back数量在n以内,引用的地址不会发生变化。vector内存也没有改变
  但如果事先告诉n的程序,这种方法是最好的。
  例:
    std::vector< int > vA;
    vA.reserve(10);
    vA.push_back(7);
    vA.push_back(6);
    vA.push_back(2);
    vA.push_back(9);
    int* pAddress = &vA[0];


方法2:
  通过构造函数告诉该容量容量
  各种带参数构造类似,这里不多举例
  例:
    std::vector< int > vA(10);
    int* pAddress = &vA[0];
    pAddress[0] = 7; // 等于 vA[0] = 7;
    pAddress[1] = 6; // 等于 vA[1] = 6;
    pAddress[2] = 2; // 等于 vA[2] = 2;
    pAddress[3] = 9; // 等于 vA[3] = 9;


方法3:
  与方法1方法一样。只是调用函数是:std::vector::resize(int n);

 

再说说resize与reserve的区别
resize:新的大小 < 现有大小,会删除多余的部分
        新的大小 > 现有大小,会在现有尺部插入新的数据,这时就有可能造成容量变化
        其它情况不操作。
reserve:当前容量 < 传入容量,会根据新的容量创建内存,并复制。
         当前容量 > 传入容量,不理踩
         其它情况不操作。

阅读更多
个人分类: C++编程
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭