GUN C++ STL中的vector的内存分配器

来源:互联网 发布:软件系统简介 编辑:程序博客网 时间:2024/05/18 00:27

      • GUN C STL中的vector的内存分配器
      • allocator_traits

GUN C++ STL中的vector的内存分配器

//vector 原型  默认情况下其内存配置器为std::allocator<_Tp>template <typename _Tp, typename _Alloc = std::allocator<_Tp>>class vector : protected _Vector_base<_Tp, _Alloc>;//_Vector_base原型template <typename _Tp, typename _Alloc>struct _Vector_base{typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;//stl源码剖析上说, 这个其实就是一个allocator<U>, 见alloc_traits//_Vector_base的一个内部类, 继承了这个allocatorstruct _Vector_impl : _Tp_alloc_type{    pointer _M_start;//目前使用的空间的开始指针    pointer _M_finish;//目前使用的空间的结尾指针    pointer _M_end_of_storage;//目前可用的空间的尾指针};};

看一个vector的构造函数

//调用形式:vector<string> v(10, "asd");vector( size_type __n, //构造函数结束时,会析构这个临时对象allocator        const value_type &__value,         const allocator_type &__a = allocator_type())//此处构造一个临时的allocator对象    : _Base(__n, __a){//基类复制了这个临时对象, 生成了自己的内部类    _M_fill_initialize(__n, __value);//这个是负责构造对象的}//调用基类的这个构造函数//发现父类中并没有负责对象的构造,只是负责内存的分配_Vector_base(size_t __n, const allocator_type &__a) : _M_impl(__a){//调用_M_impl复制构造    _M_create_storage(__n);//内存貌似在这儿分配的}//调用这个内部类的构造函数_Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT    : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0){}//又调用其父类的_Tp_alloc_type复制构造函数,就是std::allocator<_Tp>//这是一个基类的protected函数void _M_create_storage(size_t __n){  this->_M_impl._M_start = this->_M_allocate(__n);//分配内存  this->_M_impl._M_finish = this->_M_impl._M_start;//里面还没有东西  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;}//这是一个基类的public函数pointer _M_allocate(size_t __n){//分配的内存大小与调用vector时设置的大小一致  //默认情况下_Tp_alloc_type是std::allocator<_Tp>, 见alloc_traits  typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;  return __n != 0 ? _Tr::allocate(_M_impl, __n) : 0;//调用该构造器的allocate函数分配内存}

再看_M_fill_initialize

void _M_fill_initialize(  size_type __n, const value_type &__value){    std::__uninitialized_fill_n_a(this->_M_impl._M_start,                                   __n,                                   __value,                                   _M_get_Tp_allocator());    this->_M_impl._M_finish = this->_M_impl._M_end_of_storage;}//头文件 stl_uninitialized.h中//此函数还有一个标准模版的版本, 最后一个参数是为了使用默认内存分配器std::allocator时使用这个版本template<typename _ForwardIterator, typename _Size, typename _Tp, typename _Allocator>void __uninitialized_fill_n_a(_ForwardIterator __first,                               _Size __n,                               const _Tp& __x,                               _Allocator& __alloc);//使用自己的分配器时调用此函数template <typename _ForwardIterator, typename _Size, typename _Tp, typename _Tp2>inline void __uninitialized_fill_n_a(_ForwardIterator __first,                                      _Size __n,                                      const _Tp& __x,                                      allocator<_Tp2>&){//最后一个参数只是为了函数匹配  std::unitialialized_fill_n(__first, __n, __x);}//unitialialized_fill_n template<typename _ForwardIterator, typename _Size, typename _Tp> inline void uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x){    //value_type 是迭代器所指向的类型, vector的迭代器其实是一个Random Access Iterator    typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;#if __cplusplus < 201103L      const bool __assignable = true;#else      // trivial types can have deleted assignment      //利用traits技法"萃取"迭代器所指对象的类型是否支持'复制构造'和'operator='操作      //不过貌似这个一直都是true,即使这两个函数被声明为delete      const bool __assignable = is_copy_assignable<_ValueType>::value;#endif    //__is_trivial 提取迭代器所指对象是否有默认的构造函数      std::__uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>::    __uninit_fill_n(__first, __n, __x);}//如果有默认构造//其中调用全局construct函数, 构造对象//如果没有默认够造函数//std::__uninitialized_fill_n<true>::__uninit_fill_n函数, 最终调用fill_n

vector是如何管理分配的内存大小的?

//左值引用版本//调用push_back(_Tp &)时, 会检查内存分配情况, 够不够新插入的元素//_Alloc_traits  typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits;void 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//没有就分配空间再构造#if __cplusplus >= 201103L        _M_emplace_back_aux(__x);#else        _M_insert_aux(end(), __x);#endif}//右值引用版本
//_M_emplace_back_aux  //声明在stl_vector.h中, 定义在vector.tcc文件中#if __cplusplus >= 201103Ltemplate<typename _Tp, typename _Alloc>template<typename... _Args>void vector<_Tp, _Alloc>::_M_emplace_back_aux(_Args&&... __args){    //从_M_check_len函数可以看出vector的内存分配策略    //原大小加上max(size(), 1)        __n就是size_type(1)    //const size_type __len = size() + std::max(size(), __n);    const size_type __len = _M_check_len(size_type(1), "vector::_M_emplace_back_aux");    pointer __new_start(this->_M_allocate(__len));//开始分配内存    pointer __new_finish(__new_start);//调节尾指针/*---------------------------------------------------------------------------------*/    __try{//为了在构造了部分对象时,发生了异常,可以析构掉之前已经构造的对象            _Alloc_traits::construct(this->_M_impl, //先构造这个push_back的元素                                __new_start + size(), //在start+size()位置构造                                std::forward<_Args>(__args)...);//forward保持其左/右值引用属性        __new_finish = 0;        __new_finish//移动元素,如果可以移动的话   C++primer 第五版 p474          = std::__uninitialized_move_if_noexcept_a          (this->_M_impl._M_start, this->_M_impl._M_finish,           __new_start, _M_get_Tp_allocator());        ++__new_finish;      }__catch(...){//如果出现异常        if (!__new_finish)//如果在设置__new_finish = 0之前构造对象就出现异常,析构这一个对象          _Alloc_traits::destroy(this->_M_impl, __new_start + size());        else          std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());        _M_deallocate(__new_start, __len);//释放这块新内存        __throw_exception_again;      }/*----------------------------------------------------------------------------------*/    std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,              _M_get_Tp_allocator());//析构对象    _M_deallocate(this->_M_impl._M_start,              this->_M_impl._M_end_of_storage              - this->_M_impl._M_start);//释放内存    this->_M_impl._M_start = __new_start;    this->_M_impl._M_finish = __new_finish;    this->_M_impl._M_end_of_storage = __new_start + __len;//调节指针}#endif

allocator_traits

这个类中有内存配置器的大部分接口函数, 只是参数加一个allocator_type, 然后调用

//模版定义template <typename _Alloc>struct allocator_traits : __allocator_traits_base;//std::allocator即stl默认的内存配置器的特例化版本template <typename _Tp>struct allocator_traits<allocator<_Tp>>;
原创粉丝点击