stl vector 源码分析

template <class _Ty, class _Alloc = allocator<_Ty>>
class vector { // varying size array of values
//_Ty 我们常用传入的数据类型
//_Alloc vector的内存分配器,其默认值是allocator<_Ty> 这东西是stl的默认内存分配器,其中直接是用new分配 delete释放,详情看下allocator的源码分析
	_Compressed_pair<_Alty, _Scary_val> _Mypair;//vector中包含的成员数据
//其中_Compressed_pair源码如下
template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first
public:
    _Ty2 _Myval2;//_Compressed_pair 包含两部分,一个_Ty1 子对象的部分,另一部就是 _Myval2
//不要被上面这玩意吓到,无关大局,我们主要研究逻辑,不研究数据的表现形式
//然后看 vector构造函数,选一个好了
//不传入任何参数
   _CONSTEXPR20 vector() noexcept(is_nothrow_default_constructible_v<_Alty>) : _Mypair(_Zero_then_variadic_args_t{}) {
        _Mypair._Myval2._Alloc_proxy(_GET_PROXY_ALLOCATOR(_Alty, _Getal()));
        //_Getal() 获取_Mypair的前面一部分_Ty1 子对象的部分
    }
    //其中_Alloc_proxy的源码如下
template <class _Alloc> //其中_Alloc已经与我们传入的数据类型_Ty绑定
_CONSTEXPR20 void _Alloc_proxy(_Alloc&& _Al) {//这个函数属于_Myval2父类的一个成员
	_Container_proxy* const _New_proxy = _Unfancy(_Al.allocate(1));//在没有任何参数的情况下 只创建一个对象(我们需要保存的)放入vector容器中
  _Construct_in_place(*_New_proxy, this);//在*_New_proxy这个位置初始化,一个_Container_proxy
  _Myproxy            = _New_proxy;			//将创建的内存保存起来
  _New_proxy->_Mycont = this;						//这个应该是多余的初始化的时候,就绑定了
}
//然后看vector的push_back
_CONSTEXPR20 void push_back(const _Ty& _Val) { // insert element at end, provide strong guarantee
	_Emplace_one_at_back(_Val);
}
    template <class... _Valty>
    _CONSTEXPR20 _Ty& _Emplace_one_at_back(_Valty&&... _Val) {
        auto& _My_data   = _Mypair._Myval2;
        pointer& _Mylast = _My_data._Mylast;
        if (_Mylast != _My_data._Myend) {//pop出去而空闲出来的,或者clear之后腾出来的空间
        //如果我们初始化给了一定空间,但是不调用clear,或pop这部分数据出去,初始化这部分数据会一直保存到容器失效
            return _Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...);
        }
        return *_Emplace_reallocate(_Mylast, _STD forward<_Valty>(_Val)...);//没有才申请
    }
template <class... _Valty>
    _CONSTEXPR20 pointer _Emplace_reallocate(const pointer _Whereptr, _Valty&&... _Val) {
        _Alty& _Al        = _Getal();//获取_Mypair的前面部分即 对象分配器
        auto& _My_data    = _Mypair._Myval2;
        pointer& _Myfirst = _My_data._Myfirst;
        pointer& _Mylast  = _My_data._Mylast;
        _STL_INTERNAL_CHECK(_Mylast == _My_data._Myend); // 如果有空闲内存,它不应进入这里的
        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;//新的数目,插入一个嘛
        const size_type _Newcapacity = _Calculate_growth(_Newsize);//计算容器的增长量
        //增长算法 new_size = old_size + old_size / 2;
        const pointer _Newvec           = _Al.allocate(_Newcapacity);//根据新的大小重新分配内存,因为已经没有空闲空间了嘛
        const pointer _Constructed_last = _Newvec + _Whereoff + 1;
        pointer _Constructed_first      = _Constructed_last;
        _TRY_BEGIN
        _Alty_traits::construct(_Al, _Unfancy(_Newvec + _Whereoff), _STD forward<_Valty>(_Val)...);
   //利用_Newvec + _Whereoff这块地址,构造一个和_Newvec同类型的对象(_Valty这个类型),从这里拷贝或移动,有移动的情况优先移动构造
        _Constructed_first = _Newvec + _Whereoff;
        if (_Whereptr == _Mylast) { // at back, provide strong guarantee
            if constexpr (is_nothrow_move_constructible_v<_Ty> || !is_copy_constructible_v<_Ty>) {
                _Uninitialized_move(_Myfirst, _Mylast, _Newvec, _Al);
            } else {
                _Uninitialized_copy(_Myfirst, _Mylast, _Newvec, _Al);
            }
        } else { // provide basic guarantee
            _Uninitialized_move(_Myfirst, _Whereptr, _Newvec, _Al);
            _Constructed_first = _Newvec;
            _Uninitialized_move(_Whereptr, _Mylast, _Newvec + _Whereoff + 1, _Al);
        }
        _CATCH_ALL
        _Destroy_range(_Constructed_first, _Constructed_last, _Al);
        _Al.deallocate(_Newvec, _Newcapacity);
        _RERAISE;
        _CATCH_END
        _Change_array(_Newvec, _Newsize, _Newcapacity);//修改数组结构,下面看这个函数内部
        return _Newvec + _Whereoff;
    }
_CONSTEXPR20 void _Change_array(const pointer _Newvec, const size_type _Newsize, const size_type _Newcapacity) {
        // orphan all iterators, discard old array, acquire new array
        auto& _Al         = _Getal();
        auto& _My_data    = _Mypair._Myval2;
        pointer& _Myfirst = _My_data._Myfirst;
        pointer& _Mylast  = _My_data._Mylast;
        pointer& _Myend   = _My_data._Myend;
        _My_data._Orphan_all();
        if (_Myfirst) { // 如果之前存在就先删除,这一部分就是我们正常所说的比较耗费性能的地方啦
            _Destroy_range(_Myfirst, _Mylast, _Al);//依次调用数组成员的析构函数
            _ASAN_VECTOR_REMOVE;
            _Al.deallocate(_Myfirst, static_cast<size_type>(_Myend - _Myfirst));//清除掉整块内存
        }
        _Myfirst = _Newvec;			//重新构建新的数组信息
        _Mylast  = _Newvec + _Newsize;
        _Myend   = _Newvec + _Newcapacity;
        _ASAN_VECTOR_CREATE;
    }
//看我push 我们再看看下pop
    _CONSTEXPR20 void pop_back() noexcept /* strengthened */ {
        auto& _My_data   = _Mypair._Myval2;
        pointer& _Mylast = _My_data._Mylast;
        _Orphan_range(_Mylast - 1, _Mylast);//调整容器大小
        _Alty_traits::destroy(_Getal(), _Unfancy(_Mylast - 1));//只是调用析构函数,并不释放内存
        --_Mylast;//调整容器尾部指针
    }

allocator

//allocator 主要函数就这两个,一个分配一个回收内存
   	_NODISCARD_RAW_PTR_ALLOC _CONSTEXPR20 __declspec(allocator) _Ty* allocate(_CRT_GUARDOVERFLOW const size_t _Count){
        static_assert(sizeof(value_type) > 0, "value_type must be complete before calling allocate.");
        return static_cast<_Ty*>(_Allocate<_New_alignof<_Ty>>(_Get_size_of_n<sizeof(_Ty)>(_Count)));
    }
//_CONSTEXPR20 	宏定义的关键字,在c++20 表示 constexpr, c++20之前 表示inline
//constexpr			常量表达式,表明编译时就需要计算这个函数的值,如果需要的话
//分配内存是调用的是 _Deallocate 常规的库函数,默认使用_Default_allocate_traits 来进行内存分配,如下
_Traits::_Allocate(_Bytes);//_Traits为_Default_allocate_traits 其中_Allocate中,这个只是小内存分配,大内存分配其实也一样,只是多做了写记录,也是调用这个玩意
//_Default_allocate_traits 类中
void* _Allocate(const size_t _Bytes) {
    return ::operator new(_Bytes);//所以内存还是直接new出来的
}

//再来看释放内存
    _CONSTEXPR20 void deallocate(_Ty* const _Ptr, const size_t _Count) {
        _STL_ASSERT(_Ptr != nullptr || _Count == 0, "null pointer cannot point to a block of non-zero size");
        // no overflow check on the following multiply; we assume _Allocate did that check
        _Deallocate<_New_alignof<_Ty>>(_Ptr, sizeof(_Ty) * _Count);
    }
//_New_alignof<_Ty> 取最大的对齐方式,还是啥的,单个块的大小吧,最小为8
//主要调用_Deallocate进行内存释放,其函数内部主要调用   ::operator delete(_Ptr, _Bytes);进行内存释放
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值