C++ STL 容器设计与实现分析 -- vector

2、vector

vector 属于动态数组,自动控制存储空间,根据需要进行扩展和收缩。通常拥有额外的空间以处理未来的增长,这样,每次插入元素时,不需要每次重新分配内存,仅在附加内存耗尽时才重新分配。

可使用 capacity() 查看分配的内存总量,也可以调用 shrink_to_fit() 将额外的内存返回给系统。如果事先知道元素数量,可调用 reserve(n) 一次性分配内存。

vector 继承于 _Vector_base,_Vector_base 只有一个 _Vector_impl 类型的成员变量。

  template<typename _Tp, typename _Alloc>
    struct _Vector_base
    {
      struct _Vector_impl_data
      {
    pointer _M_start;
    pointer _M_finish;
    pointer _M_end_of_storage;
        /* ... */
      };

      struct _Vector_impl
    : public _Tp_alloc_type, public _Vector_impl_data
      {
    /* ... */
      };

    public:
      _Vector_impl _M_impl;
      /* ... */
    };

  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class vector : protected _Vector_base<_Tp, _Alloc>
    {
      /* ... */
    };

抽丝剥茧,vector 实现只用到三个指针:

  • _M_start:内存起始地址
  • _M_finish:vector 结束地址
  • _M_end_of_storage:内存结束地址

2.1、 _Vector_base

    _Vector_base 负责管理 vector 内存的申请与释放。

    _M_allocate() 和 _M_deallocate() 两个函数分别负责申请和释放内存,_M_create_storage(n) 申请 n 个对象的空间,然后初始化三个指针成员。

          _GLIBCXX20_CONSTEXPR
          pointer
          _M_allocate(size_t __n)
          {
        typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
        return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer();
          }
    
          _GLIBCXX20_CONSTEXPR
          void
          _M_deallocate(pointer __p, size_t __n)
          {
        typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;
        if (__p)
          _Tr::deallocate(_M_impl, __p, __n);
          }
    
        protected:
          _GLIBCXX20_CONSTEXPR
          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;
          }
    

    _Vector_base 构造函数调用 _M_create_storage() 函数申请 n 个对象空间。

          _GLIBCXX20_CONSTEXPR
          _Vector_base(size_t __n, const allocator_type& __a)
          : _M_impl(__a)
          { _M_create_storage(__n); }
    

    2.2、vector::type

      template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
        class vector : protected _Vector_base<_Tp, _Alloc>
        {
          typedef _Vector_base<_Tp, _Alloc>            _Base;
          typedef typename _Base::_Tp_alloc_type        _Tp_alloc_type;
          typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>    _Alloc_traits;
    
        public:
          typedef _Tp                    value_type;
          typedef typename _Base::pointer            pointer;
          typedef typename _Alloc_traits::const_pointer    const_pointer;
          typedef typename _Alloc_traits::reference        reference;
          typedef typename _Alloc_traits::const_reference    const_reference;
          typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;
          typedef __gnu_cxx::__normal_iterator<const_pointer, vector>
          const_iterator;
          typedef std::reverse_iterator<const_iterator>    const_reverse_iterator;
          typedef std::reverse_iterator<iterator>        reverse_iterator;
          typedef size_t                    size_type;
          typedef ptrdiff_t                    difference_type;
          typedef _Alloc                    allocator_type;
          /* ... */
        };
    

    2.3、vector::ctor

    构造函数分析三种

    2.3.1、vector(n)

    当构造函数指定了 vector 的大小,首先基类 _Vector_base 申请 n 个元素的内存空间(不调用元素构造函数),然后 vector 构造函数将调用 _M_default_initialize() 函数给申请的 n 个对象初始化。

          vector(size_type __n, const allocator_type& __a = allocator_type())
          : _Base(_S_check_init_len(__n, __a), __a)
          { _M_default_initialize(__n); }
    

    _M_default_initialize()

  • std::__uninitialized_default_n_a
  • std::__uninitialized_default_n
  • __uninitialized_default_n_1::__uninit_default_n
  •       _GLIBCXX20_CONSTEXPR
          void
          _M_default_initialize(size_type __n)
          {
        this->_M_impl._M_finish =
          std::__uninitialized_default_n_a(this->_M_impl._M_start, __n,
                           _M_get_Tp_allocator());
          }
    
      template<typename _ForwardIterator, typename _Size, typename _Tp>
        _GLIBCXX20_CONSTEXPR
        inline _ForwardIterator
        __uninitialized_default_n_a(_ForwardIterator __first, _Size __n,
                    allocator<_Tp>&)
        { return std::__uninitialized_default_n(__first, __n); }
    
      template<typename _ForwardIterator, typename _Size>
        _GLIBCXX20_CONSTEXPR
        inline _ForwardIterator
        __uninitialized_default_n(_ForwardIterator __first, _Size __n)
        {
          typedef typename iterator_traits<_ForwardIterator>::value_type
        _ValueType;
          // See uninitialized_fill_n for the conditions for using std::fill_n.
          constexpr bool __can_fill
        = __and_<is_integral<_Size>, is_copy_assignable<_ValueType>>::value;
    
          return __uninitialized_default_n_1<__is_trivial(_ValueType)
                         && __can_fill>::
        __uninit_default_n(__first, __n);
        }
    

    __uninitialized_default_n_1 尽可能调用 std::fill_n 处理。

      template<bool _TrivialValueType>
        struct __uninitialized_default_n_1
        {
          template<typename _ForwardIterator, typename _Size>
        _GLIBCXX20_CONSTEXPR
            static _ForwardIterator
            __uninit_default_n(_ForwardIterator __first, _Size __n)
            {
          _ForwardIterator __cur = __first;
          __try
            {
              for (; __n > 0; --__n, (void) ++__cur)
            std::_Construct(std::__addressof(*__cur));
              return __cur;
            }
          __catch(...)
            {
              std::_Destroy(__first, __cur);
              __throw_exception_again;
            }
        }
        };
    
      template<>
        struct __uninitialized_default_n_1<true>
        {
          template<typename _ForwardIterator, typename _Size>
        _GLIBCXX20_CONSTEXPR
            static _ForwardIterator
            __uninit_default_n(_ForwardIterator __first, _Size __n)
            {
          if (__n > 0)
            {
              typename iterator_traits<_ForwardIterator>::value_type* __val
            = std::__addressof(*__first);
              std::_Construct(__val); // 构造 first
              ++__first; // 剩余元素拷贝
              __first = std::fill_n(__first, __n - 1, *__val);
            }
          return __first;
        }
        };
    

    2.3.2、vector(n, val)

    当构造函数指定元素个数和值时,最终 std::uninitialized_fill_n() 会被调用,初始化对象的值。

          _GLIBCXX20_CONSTEXPR
          vector(size_type __n, const value_type& __value,
             const allocator_type& __a = allocator_type())
          : _Base(_S_check_init_len(__n, __a), __a)
          { _M_fill_initialize(__n, __value); }
    
          _GLIBCXX20_CONSTEXPR
          void
          _M_fill_initialize(size_type __n, const value_type& __value)
          {
        this->_M_impl._M_finish =
          std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value,
                        _M_get_Tp_allocator());
          }
    
      template<typename _ForwardIterator, typename _Size, typename _Tp,
           typename _Tp2>
        _GLIBCXX20_CONSTEXPR
        inline _ForwardIterator
        __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n,
                     const _Tp& __x, allocator<_Tp2>&)
        {
    #ifdef __cpp_lib_is_constant_evaluated
    /* ... */
    #endif
          return std::uninitialized_fill_n(__first, __n, __x);
        }
    

    2.3.3、vector(first, last)

          template<typename _InputIterator,
               typename = std::_RequireInputIter<_InputIterator>>
        _GLIBCXX20_CONSTEXPR
        vector(_InputIterator __first, _InputIterator __last,
               const allocator_type& __a = allocator_type())
        : _Base(__a)
        {
          _M_range_initialize(__first, __last,
                      std::__iterator_category(__first));
        }
    
          template<typename _InputIterator>
        _GLIBCXX20_CONSTEXPR
        void
        _M_range_initialize(_InputIterator __first, _InputIterator __last,
                    std::input_iterator_tag)
        {
          __try {
            for (; __first != __last; ++__first)
    #if __cplusplus >= 201103L
              emplace_back(*__first); // 逐一执行 emplace_back
    #else
    #endif
          } __catch(...) {
            clear();
            __throw_exception_again;
          }
        }
    
          template<typename _ForwardIterator>
        _GLIBCXX20_CONSTEXPR
        void
        _M_range_initialize(_ForwardIterator __first, _ForwardIterator __last,
                    std::forward_iterator_tag)
        {
          const size_type __n = std::distance(__first, __last);
          this->_M_impl._M_start
            = this->_M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator()));
          this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;
          this->_M_impl._M_finish =
            std::__uninitialized_copy_a(__first, __last,
                        this->_M_impl._M_start,
                        _M_get_Tp_allocator()); // 拷贝元素
        }
    
    

    2.4、vector::dctor

    vector 的析构函数调用 std::_Destroy() 函数将 [start, finish) 范围的对象析构。std::_Destroy() 根据对象类型做优化:如果对象的析构函数是 default 或者编译器自动生成的,std::_Destroy() 什么都不做,否则依次调用对象的析构函数。

          _GLIBCXX20_CONSTEXPR
          ~vector() _GLIBCXX_NOEXCEPT
          {
        std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                  _M_get_Tp_allocator());
        _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC;
          }
    

    2.5、push_back

    如果有剩余空间,在末尾的位置构造一个对象

          void
          push_back(const value_type& __x)
          {
        if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
          {
            _GLIBCXX_ASAN_ANNOTATE_GROW(1);
            _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                         __x);
            ++this->_M_impl._M_finish;
            _GLIBCXX_ASAN_ANNOTATE_GREW(1);
          }
        else
          _M_realloc_insert(end(), __x);
          }
    

    否则调用 _M_realloc_insert() 进行扩容

    • 调用 _M_check_len() 函数计算新的长度
    • 在新的内存地址构造新插入的元素
    • 将就的元素拷贝到新内存
    • 旧元素析构,旧内存释放

    在元素构造和拷贝过程中,如果有任何异常抛出,已经构造的对象将被析构。

    #if __cplusplus >= 201103L
      template<typename _Tp, typename _Alloc>
        template<typename... _Args>
          _GLIBCXX20_CONSTEXPR
          void
          vector<_Tp, _Alloc>::
          _M_realloc_insert(iterator __position, _Args&&... __args)
    #else
    /* ... */
    #endif
        {
          const size_type __len =
        _M_check_len(size_type(1), "vector::_M_realloc_insert");
          pointer __old_start = this->_M_impl._M_start;
          pointer __old_finish = this->_M_impl._M_finish;
          const size_type __elems_before = __position - begin();
          pointer __new_start(this->_M_allocate(__len)); // 扩容
          pointer __new_finish(__new_start);
          __try
        {
          // The order of the three operations is dictated by the C++11
          // case, where the moves could alter a new element belonging
          // to the existing vector.  This is an issue only for callers
          // taking the element by lvalue ref (see last bullet of C++11
          // [res.on.arguments]).
          _Alloc_traits::construct(this->_M_impl,
                       __new_start + __elems_before,
    #if __cplusplus >= 201103L
                       std::forward<_Args>(__args)...); // 构造插入元素
    #else
                       __x);
    #endif
          __new_finish = pointer();
    
    #if __cplusplus >= 201103L
          if _GLIBCXX17_CONSTEXPR (_S_use_relocate())
            {
              __new_finish = _S_relocate(__old_start, __position.base(),
                         __new_start, _M_get_Tp_allocator()); // 拷贝旧元素
    
              ++__new_finish;
    
              __new_finish = _S_relocate(__position.base(), __old_finish,
                         __new_finish, _M_get_Tp_allocator()); // 拷贝旧元素
            }
          else
    #endif
            {
              __new_finish
            = std::__uninitialized_move_if_noexcept_a
            (__old_start, __position.base(),
             __new_start, _M_get_Tp_allocator());
    
              ++__new_finish;
    
              __new_finish
            = std::__uninitialized_move_if_noexcept_a
            (__position.base(), __old_finish,
             __new_finish, _M_get_Tp_allocator());
            }
        }
          __catch(...) // 出现异常,析构对象,释放内存
        {
          if (!__new_finish)
            _Alloc_traits::destroy(this->_M_impl,
                       __new_start + __elems_before);
          else
            std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
          _M_deallocate(__new_start, __len);
          __throw_exception_again;
        }
    #if __cplusplus >= 201103L
          if _GLIBCXX17_CONSTEXPR (!_S_use_relocate())
    #endif
        std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());
          _GLIBCXX_ASAN_ANNOTATE_REINIT;
          _M_deallocate(__old_start,
                this->_M_impl._M_end_of_storage - __old_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;
        }
    

    _M_check_len() 函数可以看到,新的 size 时原来的两倍

          _GLIBCXX20_CONSTEXPR
          size_type
          _M_check_len(size_type __n, const char* __s) const
          {
        if (max_size() - size() < __n)
          __throw_length_error(__N(__s));
    
        const size_type __len = size() + (std::max)(size(), __n);
        return (__len < size() || __len > max_size()) ? max_size() : __len;
          }
    

    emplace_back() 和 push_back() 类似,只不过 emplace_back() 调用的构造函数,push_back() 调用赋值构造函数。

    #if __cplusplus >= 201103L
      template<typename _Tp, typename _Alloc>
        template<typename... _Args>
    #if __cplusplus > 201402L
          _GLIBCXX20_CONSTEXPR
          typename vector<_Tp, _Alloc>::reference
    #else
          void
    #endif
          vector<_Tp, _Alloc>::
          emplace_back(_Args&&... __args)
          {
        if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
          {
            _GLIBCXX_ASAN_ANNOTATE_GROW(1);
            _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                         std::forward<_Args>(__args)...);
            ++this->_M_impl._M_finish;
            _GLIBCXX_ASAN_ANNOTATE_GREW(1);
          }
        else
          _M_realloc_insert(end(), std::forward<_Args>(__args)...);
    #if __cplusplus > 201402L
        return back();
    #endif
          }
    #endif
    

    2.6、pop_back()

          _GLIBCXX20_CONSTEXPR
          void
          pop_back() _GLIBCXX_NOEXCEPT
          {
        __glibcxx_requires_nonempty();
        --this->_M_impl._M_finish;
        _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
        _GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
          }
    

    2.7、insert()

    vector::insert() 函数有多种类型,如果剩余空间不能够存放插入元素,需要扩容后。

    2.7.1、insert(pos, val) / vector::insert(pos, rval)

    insert() 函数接受左值和右值参数,两者处理逻辑相同。

    • 还有剩余空间末尾插入,在末尾构造中间插入,调用 _M_insert_aux() 函数处理
    • _M_realloc_insert() 扩容插入

    插入的元素可能是 vector 中已有的元素,而 _M_insert_aux() 内部会移动元素(如果元素支持移动语义操作,使用移动语义),所以当传入参数是左值时,为了放置移动后元素失效,需要构造一个临时变量,当作拷贝。

      template<typename _Tp, typename _Alloc>
        _GLIBCXX20_CONSTEXPR
        typename vector<_Tp, _Alloc>::iterator
        vector<_Tp, _Alloc>::
    #if __cplusplus >= 201103L
        insert(const_iterator __position, const value_type& __x)
    #else
    /* ... */
    #endif
        {
          const size_type __n = __position - begin();
          if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
        if (__position == end()) // 插入位置在末尾,直接构造
          {
            _GLIBCXX_ASAN_ANNOTATE_GROW(1);
            _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                         __x);
            ++this->_M_impl._M_finish;
            _GLIBCXX_ASAN_ANNOTATE_GREW(1);
          }
        else
          {
    #if __cplusplus >= 201103L
            const auto __pos = begin() + (__position - cbegin());
            // __x could be an existing element of this vector, so make a
            // copy of it before _M_insert_aux moves elements around.
            _Temporary_value __x_copy(this, __x); // 构造一个临时变量
            _M_insert_aux(__pos, std::move(__x_copy._M_val())); // 移动后插入
    #else
    /* ... */
    #endif
          }
          else
    #if __cplusplus >= 201103L
        _M_realloc_insert(begin() + (__position - cbegin()), __x); // 扩容
    #else
    /* ... */
    #endif
    
          return iterator(this->_M_impl._M_start + __n);
        }
    

    传入 insert() 函数的是右值,和传入左值的 insert() 逻辑相同

          _GLIBCXX20_CONSTEXPR
          iterator
          insert(const_iterator __position, value_type&& __x)
          { return _M_insert_rval(__position, std::move(__x)); }
    
      template<typename _Tp, typename _Alloc>
        _GLIBCXX20_CONSTEXPR
        auto
        vector<_Tp, _Alloc>::
        _M_insert_rval(const_iterator __position, value_type&& __v) -> iterator
        {
          const auto __n = __position - cbegin();
          if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
        if (__position == cend())
          {
            _GLIBCXX_ASAN_ANNOTATE_GROW(1);
            _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                         std::move(__v));
            ++this->_M_impl._M_finish;
            _GLIBCXX_ASAN_ANNOTATE_GREW(1);
          }
        else
          _M_insert_aux(begin() + __n, std::move(__v));
          else
        _M_realloc_insert(begin() + __n, std::move(__v));
    
          return iterator(this->_M_impl._M_start + __n);
        }
    

    _M_insert_aux() 函数首先将末尾元素移动,然后再为插入元素腾地方,最后插入元素。

      template<typename _Tp, typename _Alloc>
        template<typename _Arg>
          _GLIBCXX20_CONSTEXPR
          void
          vector<_Tp, _Alloc>::
          _M_insert_aux(iterator __position, _Arg&& __arg)
        {
          _GLIBCXX_ASAN_ANNOTATE_GROW(1);
          _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
                       _GLIBCXX_MOVE(*(this->_M_impl._M_finish - 1))); // 构造末尾元素
          ++this->_M_impl._M_finish;
          _GLIBCXX_ASAN_ANNOTATE_GREW(1);
    #if __cplusplus < 201103L
    /* ... */
    #endif // 将 [pos, finish - 2) 移动到 [pos + 1, finish - 1)
          _GLIBCXX_MOVE_BACKWARD3(__position.base(),
                      this->_M_impl._M_finish - 2,
                      this->_M_impl._M_finish - 1);
    #if __cplusplus < 201103L
          *__position = __x_copy; // 插入元素
    #else
    /* ... */
    #endif
        }
    

    _M_realloc_insert() 的逻辑如下

    • 2 被扩容
    • 在插入位置出构造插入元素
    • 移动原 vector 的元素
    • 析构原 vector 元素,释放原 vector 内存

    如果在构造或者移动元素过程中出现异常,新内存上所有已经构造的函数都会被析构,内存也被释放。

    2.7.2、insert(pos, n, val)

          _GLIBCXX20_CONSTEXPR
          iterator
          insert(const_iterator __position, size_type __n, const value_type& __x)
          {
        difference_type __offset = __position - cbegin();
        _M_fill_insert(begin() + __offset, __n, __x);
        return begin() + __offset;
          }
    

    _M_fill_insert() 定义如下,逻辑大致和 _M_realloc_insert() 相同

      template<typename _Tp, typename _Alloc>
        _GLIBCXX20_CONSTEXPR
        void
        vector<_Tp, _Alloc>::
        _M_fill_insert(iterator __position, size_type __n, const value_type& __x)
        {
          if (__n != 0)
        {
          if (size_type(this->_M_impl._M_end_of_storage
                - this->_M_impl._M_finish) >= __n)
            { // 剩余空间能够存放 n 数据
    #if __cplusplus < 201103L
              value_type __x_copy = __x;
    #else
              _Temporary_value __tmp(this, __x);
              value_type& __x_copy = __tmp._M_val();
    #endif
              const size_type __elems_after = end() - __position;
              pointer __old_finish(this->_M_impl._M_finish);
              if (__elems_after > __n) // initialized 空间大于 n
            {
              _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
              std::__uninitialized_move_a(this->_M_impl._M_finish - __n,
                              this->_M_impl._M_finish,
                              this->_M_impl._M_finish,
                              _M_get_Tp_allocator()); // 腾出位置
              this->_M_impl._M_finish += __n;
              _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
              _GLIBCXX_MOVE_BACKWARD3(__position.base(),
                          __old_finish - __n, __old_finish);
              std::fill(__position.base(), __position.base() + __n,
                    __x_copy); // 填充插入元素
            }
              else // initialized 空间小于 n
            {
              _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
              this->_M_impl._M_finish =
                std::__uninitialized_fill_n_a(this->_M_impl._M_finish,
                              __n - __elems_after,
                              __x_copy,
                              _M_get_Tp_allocator()); // 在内存上构造一部分
              _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);
              std::__uninitialized_move_a(__position.base(), __old_finish,
                              this->_M_impl._M_finish,
                              _M_get_Tp_allocator()); // 腾位置
              this->_M_impl._M_finish += __elems_after;
              _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
              std::fill(__position.base(), __old_finish, __x_copy); // 填充数据
            }
            }
          else // 扩容
            {
              const size_type __len =
            _M_check_len(__n, "vector::_M_fill_insert");
              const size_type __elems_before = __position - begin();
              pointer __new_start(this->_M_allocate(__len));
              pointer __new_finish(__new_start);
              __try
            {
              // See _M_realloc_insert above.
              std::__uninitialized_fill_n_a(__new_start + __elems_before,
                            __n, __x,
                            _M_get_Tp_allocator()); // 插入元素
              __new_finish = pointer();
    
              __new_finish
                = std::__uninitialized_move_if_noexcept_a
                (this->_M_impl._M_start, __position.base(),
                 __new_start, _M_get_Tp_allocator()); // 拷贝原来的元素
    
              __new_finish += __n;
    
              __new_finish
                = std::__uninitialized_move_if_noexcept_a
                (__position.base(), this->_M_impl._M_finish,
                 __new_finish, _M_get_Tp_allocator()); // 拷贝原来的元素
            }
              __catch(...) // 出现异常,析构对象,释放内存
            {
              if (!__new_finish)
                std::_Destroy(__new_start + __elems_before,
                      __new_start + __elems_before + __n,
                      _M_get_Tp_allocator());
              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());
              _GLIBCXX_ASAN_ANNOTATE_REINIT;
              _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;
            }
        }
        }
    
欢迎关注公众号“源知源为”,阅读更多技术干货

#C++##STL##vector#
C/C++基础 文章被收录于专栏

C/C++ 语言基础

全部评论

相关推荐

勤劳的香菇求被捞求offer:满帮笔试都不给我发 似乎被卡本了
投递满帮集团等公司10个岗位
点赞 评论 收藏
分享
1 4 评论
分享
牛客网
牛客企业服务