C++_泛型编程与标准库(七)
参考:《侯捷泛化编程与标准库》、VC2019
图中标红部分为自己的笔记理解
1、深度探索vector
-
笔者觉得在最新的VC2019下不是二倍增长,虽然是几何增长,但是增加的是之前的1/2;不是完全二倍增长
-
在VC2019的32位程序下,vector类型大小是16位的,其中包含了3个4位的功能同start,finish,end_of_storage的指针,还有4位是继承基类容器(
_Container_base12
)里的指针而来的四个字节;struct _Container_base12 { _Container_proxy* _Myproxy = nullptr; } template <class _Val_types> class _Vector_val : public _Container_base { public: pointer _Myfirst; // pointer to beginning of array pointer _Mylast; // pointer to current end of sequence pointer _Myend; // pointer to end of array };
VC2019push_back()调用的是emplace_back(),而emplace_back()的处理方式与侯捷老师说的gnu2.9的类似
_CONSTEXPR20_CONTAINER void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
emplace_back(_Val);//push_back()调用emplace_back()
}
template <class... _Valty>
_CONSTEXPR20_CONTAINER 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)...);
}
_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
}
2、GNU2.9的vector容器增长与VC2019的区别
-
GNU2.9的增长
大量调用构造与析构
-
VC2019的增长,只增长之前的1/2
template <class... _Valty>
_CONSTEXPR20_CONTAINER 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;//mypair是vector类中的_Compressed_pair的类型
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();
}
const size_type _Newsize = _Oldsize + 1;//新空间等于旧空间+1
const size_type _Newcapacity = _Calculate_growth(_Newsize);//新容量等于_Oldcapacity + _Oldcapacity / 2;或者_Newsize
const pointer _Newvec = _Al.allocate(_Newcapacity);//分配新内存,返回新空间地址(指针)
const pointer _Constructed_last = _Newvec + _Whereoff + 1;
pointer _Constructed_first = _Constructed_last;//应当存放新data的空间
_TRY_BEGIN//尝试构造
_Alty_traits::construct(_Al, _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...);
_Constructed_first = _Newvec + _Whereoff;
if (_Whereptr == _Mylast) { // at back, provide strong guarantee
_Umove_if_noexcept(_Myfirst, _Mylast, _Newvec);
} else { // provide basic guarantee
_Umove(_Myfirst, _Whereptr, _Newvec);
_Constructed_first = _Newvec;
_Umove(_Whereptr, _Mylast, _Newvec + _Whereoff + 1);
}
_CATCH_ALL//异常则释放空间
_Destroy(_Constructed_first, _Constructed_last);
_Al.deallocate(_Newvec, _Newcapacity);
_RERAISE;
_CATCH_END
_Change_array(_Newvec, _Newsize, _Newcapacity);
return _Newvec + _Whereoff;//返回新data数据指针
}
_CONSTEXPR20_CONTAINER size_type _Calculate_growth(const size_type _Newsize) const {
// given _Oldcapacity and _Newsize, calculate geometric growth
const size_type _Oldcapacity = capacity();
const auto _Max = max_size();
if (_Oldcapacity > _Max - _Oldcapacity / 2) {
return _Max; // geometric growth would overflow
}
const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2;//在此处增加了之前1/2的空间
if (_Geometric < _Newsize) {
return _Newsize; // geometric growth would be insufficient
}
return _Geometric; // geometric growth is sufficient
}