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部分源码,如有错误,请读者指正!