c++ vector的size与capacity函数的区别。

一、vector的基本知识

初始化等一些基本操作请看这篇博客
为了区分size与capacity,以及capacity的增长规律。我去看了c++ vector官网,以及c++的源码。大家也可以移至官网自行查看,养成查手册的好习惯,以下是我摘抄的重点,以及结合源码进行的分析。

二、size

这是上述网页中的描述,返回vector的元素数目,还特地提到,不等于存储容量。
在这里插入图片描述
这是官网中给出的例子。

// vector::size
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myints;
  std::cout << "0. size: " << myints.size() << '\n';

  for (int i=0; i<10; i++) myints.push_back(i);
  std::cout << "1. size: " << myints.size() << '\n';

  myints.insert (myints.end(),10,100);
  std::cout << "2. size: " << myints.size() << '\n';

  myints.pop_back();
  std::cout << "3. size: " << myints.size() << '\n';

  return 0;
}

输出,这个没有疑问,就是有多少元素。

0. size: 0
1. size: 10
2. size: 20
3. size: 19

三、capacity

这是官网给出的介绍,返回分配的存储容量规模,大于或等于size,这样分配是为了防止每次有新数据push进来的重新分配。
在这里插入图片描述

3.1、具体是怎么增长的

依STL版本而定。
首先来看一个博主进行的代码测试
接下来我在这两种环境中,比对了源码。
至于怎么查看自己的STL版本!!!有没有大佬能解答一下?
1、首先来看virtual studio环境中,我的vector源码在如下路径中:
Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include.
首先上文介绍到,当容量不足时,会自动增长,那么什么时候会自动增长?首先想到的是调用push_back函数时:

void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
		emplace_back(_Val);
    }

void push_back(_Ty&& _Val) { // insert by moving into element at end, provide strong guarantee
		emplace_back(_STD move(_Val));
    }

然后查看emplace_back函数源码:

decltype(auto) emplace_back(_Valty&&... _Val) {
        // insert by perfectly forwarding into element at end, provide strong guarantee
        auto& _My_data   = _Mypair._Myval2;
        pointer& _Mylast = _My_data._Mylast;
        if (_Mylast != _My_data._Myend) {
        //返回了一个函数,这个函数是放回有可用的空间,可见这种情况是不需要增加分配。
            return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
        }
		//所以重点在reallocate函数中
        _Ty& _Result = *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);
#if _HAS_CXX17
        return _Result;
#else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv
        (void) _Result;
#endif // _HAS_CXX17
    }

查看_Emplace_reallocate函数源码:

template <class... _Valty>
    pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val) {
        // reallocate and insert by perfectly forwarding _Val at _Whereptr
        _Alty& _Al        = _Getal();
        auto& _My_data    = _Mypair._Myval2;
        pointer& _Myfirst = _My_data._Myfirst;
        pointer& _Mylast  = _My_data._Mylast;

        _STL_INTERNAL_CHECK(_Mylast == _My_data._Myend); // check that we have no unused capacity

        const auto _Whereoff = static_cast<size_type>(_Whereptr - _Myfirst);
        const auto _Oldsize  = static_cast<size_type>(_Mylast - _Myfirst);
		
        if (_Oldsize == max_size()) {
            _Xlength();
        }
		//重点在newsize和newcapacity两个为了增加容量而定义的变量。
        const size_type _Newsize     = _Oldsize + 1;
        const size_type _Newcapacity = _Calculate_growth(_Newsize);

        const pointer _Newvec           = _Al.allocate(_Newcapacity);
        const pointer _Constructed_last = _Newvec + _Whereoff + 1;
        pointer _Constructed_first      = _Constructed_last;
        ......
}

查看_Calculate_growth函数,即计算增长,重点来了!!!!

size_type _Calculate_growth(const size_type _Newsize) const {
        // given _Oldcapacity and _Newsize, calculate geometric growth
        const size_type _Oldcapacity = capacity();

        if (_Oldcapacity > max_size() - _Oldcapacity / 2) {
            return _Newsize; // geometric growth would overflow
        }
		//重点:几何增长的增量
        const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2;

        if (_Geometric < _Newsize) {
            return _Newsize; // geometric growth would be insufficient
        }

        return _Geometric; // geometric growth is sufficient
    }

可以看出每次的增量=原容量+新容量的50%,正如上述测试博文提到:当capacity<=1时,新分配的内存大小为1;当capacity>1时,则新增加的内存为原容量的50%(如果不为整数,则直接舍弃小数)。
2、Ubuntu18.04 g++环境 (gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04)):
还是首先跟踪到push_back函数

push_back(const value_type& __x)
{
	if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
	  {
	    _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,__x);
	    ++this->_M_impl._M_finish;
	  }
	else
	//realloc 重新分配
	  _M_realloc_insert(end(), __x);
}

然后查看_M_realloc_insert函数:这个函数有些复杂,建议直接掠过函数声名,而且为了缩小篇幅,把后边的大量代码省略,有兴趣的自行查看。

#if __cplusplus >= 201103L
  template<typename _Tp, typename _Alloc>
    template<typename... _Args>
      void
      vector<_Tp, _Alloc>::
      _M_realloc_insert(iterator __position, _Args&&... __args)
#else
  template<typename _Tp, typename _Alloc>
    void
    vector<_Tp, _Alloc>::
    _M_realloc_insert(iterator __position, const _Tp& __x)
#endif
{
	//重新分配的长度 __len
      const size_type __len =
	_M_check_len(size_type(1), "vector::_M_realloc_insert");
      ......
}

接下来查看_M_check_len函数,注意到函数的第一个参数是一个size_type类型的1,应该是等价于int(1)。

size_type
            _M_check_len(size_type __n, const char *__s) const
            {
                  if (max_size() - size() < __n)
                        __throw_length_error(__N(__s));
				 //_len等于原来的size+max(size, __n)
                  const size_type __len = size() + std::max(size(), __n);
                  return (__len < size() || __len > max_size()) ? max_size() : __len;
            }

可以看到,len=size+max(size, n),且n=1,所以,len=2*size
这也就解释了上述测试博文中第二种情况。

为什么函数名叫几何增长,却每次只增加50%,而函数名不叫几何增长了,却又真的采用了几何增长。才疏学浅,无法解答。。。。


由于博主能力有限,且第一次阅读c++ vector部分源码,如有错误,请读者指正!

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值