STL源码分析--vector

1. 简介

STL的容器分为序列式容器和关联式容器。vector作为序列式容器的一种,其内存模型与操作方式与数组类似,都是以一段连续的内存空间存储数据单元,区别在于数组的内存空间大小固定,不可变动,而vector可实现动态的内存迁移。当vector存储满后,会自动重新申请更大的内存空间作为新的存储容器,把旧的数据原样迁移到新的内存空间,此操作对用户层是无感知的。

用户层使用vector容器需包含头文件vector,方式为#include ,但vector的具体实现细节则在<bits/stl_vector.h>内。

STL对容器均使用模板类来实现,同时以空间分配器allocator作为内存管理者,管理着容器内存空间的申请和释放、数据对象的申请和回收,构造和析构。

vector的类图描述如下,其中的接口细节不完全展示出来。

img

  • allocator:空间分配器,管理内存的申请释放、数据对象的申请和回收,构造和析构。vector使用的空间分配器默认为std::new_alloctor;

  • _Vector_impl_data:维护容器的内存空间管理,三个指针_M_start指向内存的起始地址,_M_end_of_storage指向内存的末端地址,_M_finish指向容器最后一个元素的下一个地址空间。该类同时还提供了内存空间交换的接口,本质是交换指针。

  • _Vector_impl:继承自allocator和_Vector_Impl_data,同时该类内部还声明了_Asan模板类。

  • _Asan:GCC提供的一种内存错误检查器,这东西在编译和运行时使用,具体实现不在本博客说明。

  • _Vector_base:vector的基类。依赖_Vector_impl实现容器内存的构建、销毁。

  • vector:容器的具体实现,提供了插入、删除、定位等数据操作。

2. _Vector_impl_data的实现

struct _Vector_impl_data
{
    pointer _M_start;
    pointer _M_finish;
    pointer _M_end_of_storage;

    _GLIBCXX20_CONSTEXPR
    _Vector_impl_data() _GLIBCXX_NOEXCEPT
    : _M_start(), _M_finish(), _M_end_of_storage()
    { }

#if __cplusplus >= 201103L
    // 移动构造函数
    _GLIBCXX20_CONSTEXPR
    _Vector_impl_data(_Vector_impl_data&& __x) noexcept
    : _M_start(__x._M_start), _M_finish(__x._M_finish), _M_end_of_storage(__x._M_end_of_storage)
    { __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); }
#endif

    // 仅拷贝指针而不拷贝内存
    _GLIBCXX20_CONSTEXPR
    void _M_copy_data(_Vector_impl_data const& __x) _GLIBCXX_NOEXCEPT
    {
        _M_start = __x._M_start;
        _M_finish = __x._M_finish;
        _M_end_of_storage = __x._M_end_of_storage;
    }

    // 交换的是指针,而不是内存数据
    _GLIBCXX20_CONSTEXPR
    void _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT
    {
        _Vector_impl_data __tmp;
        __tmp._M_copy_data(*this);
        _M_copy_data(__x);
        __x._M_copy_data(__tmp);
    }
};

3. _Vector_impl的实现

struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data
{
    _GLIBCXX20_CONSTEXPR
    _Vector_impl() _GLIBCXX_NOEXCEPT_IF(is_nothrow_default_constructible<_Tp_alloc_type>::value)
    : _Tp_alloc_type()
    { }

    _GLIBCXX20_CONSTEXPR
    _Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT
    : _Tp_alloc_type(__a)
    { }

#if __cplusplus >= 201103L
    _GLIBCXX20_CONSTEXPR
    _Vector_impl(_Vector_impl&& __x) noexcept
    : _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x))
    { }

    _GLIBCXX20_CONSTEXPR
    _Vector_impl(_Tp_alloc_type&& __a) noexcept
    : _Tp_alloc_type(std::move(__a))
    { }

    _GLIBCXX20_CONSTEXPR
    _Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept
    : _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv))
    { }
#endif

#if _GLIBCXX_SANITIZE_STD_ALLOCATOR && _GLIBCXX_SANITIZE_VECTOR
    template<typename = _Tp_alloc_type>
    struct _Asan
    {
        ......
    };

    template<typename _Up>
    struct _Asan<allocator<_Up> >
    {
        ......
    };
};

4. _Vector_base的实现

template<typename _Tp, typename _Alloc>
struct _Vector_base
{
    typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template rebind<_Tp>::other _Tp_alloc_type;
    typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer pointer;
  
    struct _Vector_impl_data
    {
        // _Vector_impl_data的定义见第二节
    };
  
    struct _Vector_impl
    : public _Tp_alloc_type, public _Vector_impl_data
    {
        // _Vector_impl的定义见第三节
    };
  
public:
    typedef _Alloc allocator_type;

    // 获取空间分配器实例
    _GLIBCXX20_CONSTEXPR
    _Tp_alloc_type&
    _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT
    { return this->_M_impl; }

    _GLIBCXX20_CONSTEXPR
    const _Tp_alloc_type&
    _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT
    { return this->_M_impl; }

    _GLIBCXX20_CONSTEXPR
    allocator_type
    get_allocator() const _GLIBCXX_NOEXCEPT
    { return allocator_type(_M_get_Tp_allocator()); }

#if __cplusplus >= 201103L
    _Vector_base() = default;
#else
    _Vector_base() { }
#endif

    _GLIBCXX20_CONSTEXPR
    _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT
    : _M_impl(__a) { }


#if !_GLIBCXX_INLINE_VERSION
    _GLIBCXX20_CONSTEXPR
    _Vector_base(size_t __n)
    : _M_impl()
    { _M_create_storage(__n); }
#endif

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

#if __cplusplus >= 201103L
    _Vector_base(_Vector_base&&) = default;


# if !_GLIBCXX_INLINE_VERSION
    // 移动构造函数
    _GLIBCXX20_CONSTEXPR
    _Vector_base(_Tp_alloc_type&& __a) noexcept
    : _M_impl(std::move(__a)) { }

    // __x为要移动的_Vector_base对象,__a为要拷贝的空间分配器
    _GLIBCXX20_CONSTEXPR
    _Vector_base(_Vector_base&& __x, const allocator_type& __a)
    : _M_impl(__a)
    {
        // 当指定的分配器__a与__x的分配器相等时,直接交换__x的指针指向即可,新的容器使用的内存空间仍为__x的内存空间;
        // 当指定的分配器__a与__x的分配器不相等时,重新申请新的内存空间给新容器使用。
        // 分配器的==运算符重载见allocator的实现,其始终返回true
        if (__x.get_allocator() == __a)
            this->_M_impl._M_swap_data(__x._M_impl);
        else
        {
            size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start;
            _M_create_storage(__n);
        }
    }
# endif

    _GLIBCXX20_CONSTEXPR
    _Vector_base(const allocator_type& __a, _Vector_base&& __x)
    : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl))
    { }
#endif

    _GLIBCXX20_CONSTEXPR
    ~_Vector_base() _GLIBCXX_NOEXCEPT
    {
        _M_deallocate(_M_impl._M_start, _M_impl._M_end_of_storage - _M_impl._M_start);
    }

public:
    _Vector_impl _M_impl;

    // 构建容器的内存空间,空间大小为__n * sizeof(_Tp)
    _GLIBCXX20_CONSTEXPR
    pointer
    _M_allocate(size_t __n)
    {
        // 通过萃取机制取出空间分配器,再调用分配器提供的allocate接口申请内存空间
        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:
    // 构建容器的内存空间,空间大小为__n * sizeof(_Tp), 同时初始化三个指针
    // _M_start指向内存首地址,_M_end_of_storage指向内存末端地址,_M_finish初始等于_M_start
    _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;
    }
};

5. vector的实现

5.1 vector内的定义的类型别名

template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
class vector : protected _Vector_base<_Tp, _Alloc>
{
#ifdef _GLIBCXX_CONCEPT_CHECKS
    // Concept requirements.
    typedef typename _Alloc::value_type        _Alloc_value_type;
# if __cplusplus < 201103L
    __glibcxx_class_requires(_Tp, _SGIAssignableConcept)
# endif
    __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept)
#endif

#if __cplusplus >= 201103L
    static_assert(is_same<typename remove_cv<_Tp>::type, _Tp>::value,
        "std::vector must have a non-const, non-volatile value_type");
# if __cplusplus > 201703L || defined __STRICT_ANSI__
    static_assert(is_same<typename _Alloc::value_type, _Tp>::value,
        "std::vector must have the same value_type as its allocator");
# endif
#endif

    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;

protected:
    using _Base::_M_allocate;
    using _Base::_M_deallocate;
    using _Base::_M_impl;
    using _Base::_M_get_Tp_allocator;
    
    ......
};

5.2 vector的构造和析构

public: 

#if __cplusplus >= 201103L
vector() = default;
#else
vector() { }
#endif

explicit _GLIBCXX20_CONSTEXPR 
vector(const allocator_type& __a) _GLIBCXX_NOEXCEPT 
: _Base(__a) { }

#if __cplusplus >= 201103L

// 初始化n个数据项,数据项的初始化采用默认构造。可指定空间分配器
explicit _GLIBCXX20_CONSTEXPR
vector(size_type __n, const allocator_type& __a = allocator_type()) 
: _Base(_S_check_init_len(__n, __a), __a)
{ _M_default_initialize(__n); }

// 初始化n个数据项,数据项的初始化为__value。可指定空间分配器
_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); }

#else

// 初始化n个数据项,数据项的初始化为__value。可指定空间分配器
explicit
vector(size_type __n, const value_type& __value = value_type(), const allocator_type& __a = allocator_type())
: _Base(_S_check_init_len(__n, __a), __a)
{ _M_fill_initialize(__n, __value); }

#endif

// 拷贝构造函数,将_x的所有数据项拷贝到新的容器内。_S_select_on_copy返回一份分配器的拷贝
_GLIBCXX20_CONSTEXPR
vector(const vector& __x) 
: _Base(__x.size(), _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator()))
{
    this->_M_impl._M_finish = std::__uninitialized_copy_a(__x.begin(), __x.end(), 
        this->_M_impl._M_start, _M_get_Tp_allocator());
}

#if __cplusplus >= 201103L

vector(vector&&) noexcept = default;

// 拷贝构造函数,将_x的所有数据项拷贝到新的容器内。
// __type_identity_t 能用于在模板实参推导中建立非推导语境:
_GLIBCXX20_CONSTEXPR
vector(const vector& __x, const __type_identity_t<allocator_type>& __a)
: _Base(__x.size(), __a)
{
    this->_M_impl._M_finish = std::__uninitialized_copy_a(__x.begin(), __x.end(),
        this->_M_impl._M_start, _M_get_Tp_allocator());
}

private:

// typename _Alloc_traits::is_always_equal{} 为true_type时
_GLIBCXX20_CONSTEXPR
vector(vector&& __rv, const allocator_type& __m, true_type) noexcept
: _Base(__m, std::move(__rv))
{ }

// typename _Alloc_traits::is_always_equal{} 为false_type时
_GLIBCXX20_CONSTEXPR
vector(vector&& __rv, const allocator_type& __m, false_type)
: _Base(__m)
{
    // 当指定的分配器__m与__rv的分配器相等时,直接交换__rv的指针指向即可,新的容器使用的内存空间仍为__rv的内存空间;
    // 当指定的分配器__m与__rv的分配器不相等时,重新申请新的内存空间给新容器使用。
    // 分配器的==运算符重载见allocator的实现,其始终返回true
    if (__rv.get_allocator() == __m)
        this->_M_impl._M_swap_data(__rv._M_impl);
    else if (!__rv.empty())
    {
        this->_M_create_storage(__rv.size());
        this->_M_impl._M_finish = std::__uninitialized_move_a(__rv.begin(), __rv.end(),
            this->_M_impl._M_start, _M_get_Tp_allocator());
        __rv.clear();
    }
}

public:
// 移动构造函数,采用C++11的委托构造方式,调用其他构造函数
_GLIBCXX20_CONSTEXPR
vector(vector&& __rv, const __type_identity_t<allocator_type>& __m)
noexcept( noexcept(vector(std::declval<vector&&>(), std::declval<const allocator_type&>(),
   std::declval<typename _Alloc_traits::is_always_equal>())) )
: vector(std::move(__rv), __m, typename _Alloc_traits::is_always_equal{})
{ }

// 根据初始化列表创建容器,最终会调用数据项的n次拷贝构造函数来初始化对象。n为初始化列表的size大小
_GLIBCXX20_CONSTEXPR
vector(initializer_list<value_type> __l, const allocator_type& __a = allocator_type())
: _Base(__a)
{
    _M_range_initialize(__l.begin(), __l.end(), random_access_iterator_tag());
}
#endif


// 根据迭代器范围初始化容器,会将[first,last)范围内的数据拷贝到新容器内。
// 如果迭代器类型是forward, bidirectional或random-access,将会调用数据项的N次拷贝构造,N为迭代器范围内的数据项数目。并且不会进行内存的重新分配(reallocate)
// 如果迭代器类型是input,会进行最多2N次的拷贝构造,和logN次的内存重新分配(reallocate)
#if __cplusplus >= 201103L
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));
}
#else

// 根据迭代器范围初始化容器,会将[first,last)范围内的数据拷贝到新容器内。
// std::__is_integer模板用来判断类型是否为整型,
// 当为true时,会调用_M_fill_initialize()进行初始化,__first为数据项个数,__last为初始化的值;
// 当为false时,会调用_M_range_initialize进行初始化,__first、__last均为迭代器。
template<typename _InputIterator>
vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type())
: _Base(__a)
{
    typedef typename std::__is_integer<_InputIterator>::__type _Integral;
   _M_initialize_dispatch(__first, __last, _Integral());
}
#endif

// 析构函数仅从容器内删除数据项,如果数据项是指针,析构函数不会释放指针所指的内存空间,用户层应该在析构前主动释放内存
_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;
}

构造函数调用的几个函数接口介绍:

static _GLIBCXX20_CONSTEXPR size_type
_S_max_size(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT
{
    // std::distance(begin(), end()) cannot be greater than PTRDIFF_MAX,
    // and realistically we can't store more than PTRDIFF_MAX/sizeof(T)
    // (even if std::allocator_traits::max_size says we can).
    const size_t __diffmax = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);
    const size_t __allocmax = _Alloc_traits::max_size(__a);
    return (std::min)(__diffmax, __allocmax);
}

static _GLIBCXX20_CONSTEXPR size_type
_S_check_init_len(size_type __n, const allocator_type& __a)
{
    if (__n > _S_max_size(_Tp_alloc_type(__a)))
        __throw_length_error(__N("cannot create std::vector larger than max_size()"));
    return __n;
}

#if __cplusplus >= 201103L
// 初始化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());
}
#endif

// 初始化n个数据项,值为__value,调用的是数据项的拷贝构造、赋值运算重载、或memset
_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());
}

 // 仅当迭代器类型为input时调用
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);
#else
      push_back(*__first);
#endif
    } __catch(...) {
        clear();
        __throw_exception_again;
    }
}

// 当迭代器类型为forward、bidirectional或random-access调用,会重新申请内存并进行数据项拷贝
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());
}

#if __cplusplus < 201103L
// _Integer 为整型类型
template<typename _Integer>
void _M_initialize_dispatch(_Integer __n, _Integer __value, __true_type)
{
    this->_M_impl._M_start = _M_allocate(_S_check_init_len(
        static_cast<size_type>(__n), _M_get_Tp_allocator()));
    this->_M_impl._M_end_of_storage = this->_M_impl._M_start + static_cast<size_type>(__n);
    _M_fill_initialize(static_cast<size_type>(__n), __value);
}

// _InputIterator为迭代器类型
template<typename _InputIterator>
void _M_initialize_dispatch(_InputIterator __first, _InputIterator __last, __false_type)
{
    _M_range_initialize(__first, __last, std::__iterator_category(__first));
}
#endif

其中__uninitialized_default_n_a、__uninitialized_fill_n_a、__uninitialized_copy_a、__uninitialized_move_a几个函数是全局的内存处理函数,用于填充、拷贝、移动元素等处理,详细介绍见 STL源码分析--全局内存处理函数

几个函数模板介绍:

__type_identity_t 能用于在模板实参推导中建立非推导语境,示例如下:

template<class T>
void f(T, T);
 
template<class T>
void g(T, std::type_identity_t<T>);
 
f(4.2, 0); // 错误:对 'T' 推导出冲突的类型
g(4.2, 0); // OK :调用 g<double>

_Alloc_traits::is_always_equal 是用于得到空间分配器是否相等的特性,allocator的相等比较的意义是:一个allocator分配的空间,是否可以用另外一个allocator来释放。stl在<bits/allocator.h>定义了is_always_equal 模板始终为true_type。stl默认的空间分配器就是std::new_allocator,因为是new和delete的封装,一个std::allocator new的当然可以用另一个std::allocator来delete。

// 定义在<bits/allocator.h>中的allocator类模板中
using is_always_equal _GLIBCXX20_DEPRECATED_SUGGEST("std::allocator_traits::is_always_equal") = true_type;

// 以下均定义在<bits/alloc_traits.h>中
struct __allocator_traits_base
{
    template<typename _Tp>
    using __equal = typename _Tp::is_always_equal;
    ......
};

template<typename _Alloc>
struct allocator_traits : __allocator_traits_base
{
    // __detected_or_t用来检查类型有效性,当__equal<_Alloc>,即 _Alloc::is_always_equal有效时,is_always_equal = _Alloc::is_always_equal
    // 否则,is_always_equal = is_empty<_Alloc>::type
    // is_empty 用来判断类型是否为空类型,空类型则返回true_type, 否则返回false_type
    using is_always_equal = __detected_or_t<typename is_empty<_Alloc>::type, __equal, _Alloc>;
    ......
};

// 偏特化版本,分配器为allocator,即为std::new_allocator
template<typename _Tp>
struct allocator_traits<allocator<_Tp>>
{
    using is_always_equal = true_type;
    ......
};

template<>
struct allocator_traits<allocator<void>>
{
    using is_always_equal = true_type;
    ......
};

is_empty:如果T是空类型(即,除大小为0的位字段外,没有非静态数据成员、没有虚拟函数、没有虚拟基类和非空基类的非并集类类型),则提供等于true的成员常量值。对于任何其他类型,值都为false。

std::declval的功能:返回某个类型T的右值引用,不管该类型是否有默认构造函数或者该类型是否可以创建对象。

5.3 vector的迭代器

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;

vector定义了如上几种迭代器(其实为两种,每种各包含普通迭代器和常量迭代器),根据迭代器元素的遍历方向分为正向迭代器和反向迭代器。vector迭代器的本质为原生指针,属于Random Access Iterator,分别通过模板__normal_iterator和reverse_iterator做简单封装,实现指针的所有算数操作。__normal_iterator为正向迭代器,reverse_iterator为反向迭代器。关于迭代器的说明见 STL源码分析--迭代器iterator

5.4 vector的定界操作

// 返回指向容器第一个元素的迭代器(可读可写),迭代器是正向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
iterator begin() _GLIBCXX_NOEXCEPT
{ return iterator(this->_M_impl._M_start); }

// 返回指向容器第一个元素的迭代器(只读),迭代器是正向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_iterator begin() const _GLIBCXX_NOEXCEPT
{ return const_iterator(this->_M_impl._M_start); }

// 返回指向容器最后一个元素下一个位置的迭代器(可读可写),迭代器是正向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
iterator end() _GLIBCXX_NOEXCEPT
{ return iterator(this->_M_impl._M_finish); }

// 返回指向容器最后一个元素下一个位置的迭代器(只读),迭代器是正向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_iterator end() const _GLIBCXX_NOEXCEPT
{ return const_iterator(this->_M_impl._M_finish); }

// 返回指向容器最后一个元素的迭代器(可读可写),迭代器是反向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reverse_iterator rbegin() _GLIBCXX_NOEXCEPT
{ return reverse_iterator(end()); }

// 返回指向容器最后一个元素的迭代器(只读),迭代器是反向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_reverse_iterator rbegin() const _GLIBCXX_NOEXCEPT
{ return const_reverse_iterator(end()); }

// 返回指向容器第一个元素前一个位置的迭代器(可读可写),迭代器是反向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reverse_iterator rend() _GLIBCXX_NOEXCEPT
{ return reverse_iterator(begin()); }

// 返回指向容器第一个元素前一个位置的迭代器(只读),迭代器是反向遍历的
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_reverse_iterator rend() const _GLIBCXX_NOEXCEPT
{ return const_reverse_iterator(begin()); }

#if __cplusplus >= 201103L

// 返回指向容器第一个元素的迭代器(只读),迭代器是正向遍历的
[[__nodiscard__]] _GLIBCXX20_CONSTEXPR
const_iterator cbegin() const noexcept
{ return const_iterator(this->_M_impl._M_start); }

// 返回指向容器最后一个元素下一个位置的迭代器(只读),迭代器是正向遍历的
[[__nodiscard__]] _GLIBCXX20_CONSTEXPR
const_iterator cend() const noexcept
{ return const_iterator(this->_M_impl._M_finish); }

// 返回指向容器最后一个元素的迭代器(只读),迭代器是反向遍历的
[[__nodiscard__]] _GLIBCXX20_CONSTEXPR
const_reverse_iterator crbegin() const noexcept
{ return const_reverse_iterator(end()); }

// 返回指向容器第一个元素前一个位置的迭代器(只读),迭代器是反向遍历的
[[__nodiscard__]] _GLIBCXX20_CONSTEXPR
const_reverse_iterator crend() const noexcept
{ return const_reverse_iterator(begin()); }
#endif

// 返回容器的第一个元素的引用
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reference front() _GLIBCXX_NOEXCEPT
{
    __glibcxx_requires_nonempty();
    return *begin();
}

// 返回容器的第一个元素的常量引用
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_reference front() const _GLIBCXX_NOEXCEPT
{
    __glibcxx_requires_nonempty();
    return *begin();
}

// 返回容器最后一个元素的引用
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reference back() _GLIBCXX_NOEXCEPT
{
    __glibcxx_requires_nonempty();
    return *(end() - 1);
}

// 返回容器最后一个元素的常量引用
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_reference back() const _GLIBCXX_NOEXCEPT
{
    __glibcxx_requires_nonempty();
    return *(end() - 1);
}

// 返回容器第一个元素的地址
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
_Tp* data() _GLIBCXX_NOEXCEPT
{ return _M_data_ptr(this->_M_impl._M_start); }

_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const _Tp* data() const _GLIBCXX_NOEXCEPT
{ return _M_data_ptr(this->_M_impl._M_start); }

5.5 vector的插入和删除

5.5.1 删除

先来看下删除,删除的方式有几种,erase、pop_back以及clear,对外提供的接口有:

#if __cplusplus >= 201103L
iterator erase(const_iterator __position);
iterator erase(const_iterator __first, const_iterator __last);
#else
iterator erase(iterator __position);
iterator erase(iterator __first, iterator __last);
#endif

void pop_back();
void clear();

接口的实现细节如下:

// 删除__pos后的所有元素,含__pos。该函数私有,被erase(q1,q2), clear(), 
// resize(), _M_fill_assign,_M_assign_aux调用
_GLIBCXX20_CONSTEXPR
void _M_erase_at_end(pointer __pos) _GLIBCXX_NOEXCEPT
{
    if (size_type __n = this->_M_impl._M_finish - __pos)
    {
        std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator());
        this->_M_impl._M_finish = __pos;
		_GLIBCXX_ASAN_ANNOTATE_SHRINK(__n);
	}
}

// 删除容器__position指向的元素,返回的迭代器指向__position的下一元素(或 end())。__position删除后该迭代器失效
GLIBCXX20_CONSTEXPR
iterator
#if __cplusplus >= 201103L
erase(const_iterator __position)
{ return _M_erase(begin() + (__position - cbegin())); }
#else
erase(iterator __position)
{ return _M_erase(__position); }
#endif

// 删除容器[__first,__last)范围内的元素,返回的迭代器指向__last原先指向的元素(或end())
_GLIBCXX20_CONSTEXPR
iterator
#if __cplusplus >= 201103L
erase(const_iterator __first, const_iterator __last)
{
    const auto __beg = begin();
    const auto __cbeg = cbegin();
    return _M_erase(__beg + (__first - __cbeg), __beg + (__last - __cbeg));
}
#else
erase(iterator __first, iterator __last)
{ return _M_erase(__first, __last); }
#endif

// 清空容器
_GLIBCXX20_CONSTEXPR
void clear() _GLIBCXX_NOEXCEPT
{ _M_erase_at_end(this->_M_impl._M_start); }

_GLIBCXX20_CONSTEXPR
iterator _M_erase(iterator __position);

_GLIBCXX20_CONSTEXPR
iterator _M_erase(iterator __first, iterator __last);

// 定义与bits/vector.tcc文件中
template<typename _Tp, typename _Alloc>
_GLIBCXX20_CONSTEXPR
typename vector<_Tp, _Alloc>::iterator
vector<_Tp, _Alloc>::
_M_erase(iterator __position)
{
    // 从__position + 1起,到end(), 每个元素往前挪一个单位(拷贝或移动)
    if (__position + 1 != end())
        _GLIBCXX_MOVE3(__position + 1, end(), __position);
    // 更新_M_finish,并删除最后一个元素
    --this->_M_impl._M_finish;
    _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
    _GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
    return __position;
}

template<typename _Tp, typename _Alloc>
_GLIBCXX20_CONSTEXPR
typename vector<_Tp, _Alloc>::iterator
vector<_Tp, _Alloc>::
_M_erase(iterator __first, iterator __last)
{
    if (__first != __last)
    {
        // 将[__last, end())范围内的数据拷到__first所指的内存空间上
        if (__last != end())
            _GLIBCXX_MOVE3(__last, end(), __first);
        // end() - __last 为拷贝或移动的数据项个数,所以__first.base() + (end() - __last)就是为最后要删除的起始地址
        _M_erase_at_end(__first.base() + (end() - __last));
    }
    return __first;
}

// 定义于<bits/stl_algobase.h>
#if __cplusplus >= 201103L
#define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::move(_Tp, _Up, _Vp)
#else
#define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp)
#endif

// 删除末端的一个元素
_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);
}

iterator _M_erase(iterator __position); 操作的示例图如下:

img

iterator _M_erase(iterator __first, iterator __last);操作的示例图如下:

img

需要注意的是,当vector存储的数据是指针时,所有的删除操作(包括erase、pop_back和clear),都只会将数据项也就是指针从容器删除,而不会释放指针所指的内存空间

5.5.2 插入

vector插入数据的方式有几种,push_back、assign、insert等 ,对外提供的接口有:

void push_back(const value_type& __x);
void assign(size_type __n, const value_type& __val);
#if __cplusplus >= 201103L
void push_back(value_type&& __x);
void emplace_back(_Args&&... __args);
iterator emplace(const_iterator __position, _Args&&... __args);
iterator insert(const_iterator __position, const value_type& __x);
iterator insert(const_iterator __position, value_type&& __x);
iterator insert(const_iterator __position, initializer_list<value_type> __l);
iterator insert(const_iterator __position, size_type __n, const value_type& __x);
iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last);
void assign(_InputIterator __first, _InputIterator __last);
void assign(initializer_list<value_type> __l);
#else
iterator insert(iterator __position, const value_type& __x);
void insert(iterator __position, size_type __n, const value_type& __x);
void insert(iterator __position, _InputIterator __first, _InputIterator __last);
void assign(_InputIterator __first, _InputIterator __last);
#endif

#if __cplusplus > 201402L
reference emplace_back(_Args&&... __args);
#endif
5.5.2.1 assign函数
_GLIBCXX20_CONSTEXPR
void assign(size_type __n, const value_type& __val)
{ _M_fill_assign(__n, __val); }
#if __cplusplus >= 201103L
template<typename _InputIterator,
typename = std::_RequireInputIter<_InputIterator>>
_GLIBCXX20_CONSTEXPR
void assign(_InputIterator __first, _InputIterator __last)
{ _M_assign_dispatch(__first, __last, __false_type()); }
#else
template<typename _InputIterator>
void assign(_InputIterator __first, _InputIterator __last)
{
    // 检查_InputIterator类型是否为整型,非整型时,为迭代器
    typedef typename std::__is_integer<_InputIterator>::__type _Integral;
    _M_assign_dispatch(__first, __last, _Integral());
}
#endif

#if __cplusplus >= 201103L
// 支持初始化列表作为参数赋值
_GLIBCXX20_CONSTEXPR
void assign(initializer_list<value_type> __l)
{
    this->_M_assign_aux(__l.begin(), __l.end(), random_access_iterator_tag());
}
#endif

// 类型_Integer为整型时调用
template<typename _Integer>
_GLIBCXX20_CONSTEXPR
void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type)
{ _M_fill_assign(__n, __val); }

// 类型_InputIterator为迭代器类型时调用
template<typename _InputIterator>
_GLIBCXX20_CONSTEXPR
void _M_assign_dispatch(_InputIterator __first, _InputIterator __last, __false_type)
{ _M_assign_aux(__first, __last, std::__iterator_category(__first)); }

// 定义于bits/vector.tcc文件
template<typename _Tp, typename _Alloc>
_GLIBCXX20_CONSTEXPR
void vector<_Tp, _Alloc>::
_M_fill_assign(size_t __n, const value_type& __val)
{
    // 如果__n大于容器容量,则需重新申请内存空间,此处创建一个临时的容器,并将其与旧容器交换指针,即交换容器的内存空间所有权
    if (__n > capacity())
    {
        vector __tmp(__n, __val, _M_get_Tp_allocator());
        __tmp._M_impl._M_swap_data(this->_M_impl);
    }
    // 如果__n大于现有容器数据个数,但小于容器容量,则先将原有的数据项修改为__val,后构造剩余的数据项。
    else if (__n > size())
    {
        std::fill(begin(), end(), __val);
        const size_type __add = __n - size();
        _GLIBCXX_ASAN_ANNOTATE_GROW(__add);
        this->_M_impl._M_finish = std::__uninitialized_fill_n_a(this->_M_impl._M_finish,
                  __add, __val, _M_get_Tp_allocator());
        _GLIBCXX_ASAN_ANNOTATE_GREW(__add);
    }
    // 如果__n小于等于现有容器数据个数,则将容器前__n个数据项改为__val,后将多余的数据删除掉
    else
        _M_erase_at_end(std::fill_n(this->_M_impl._M_start, __n, __val));
}

// 仅当迭代器类型为input时调用
template<typename _Tp, typename _Alloc>
template<typename _InputIterator>
_GLIBCXX20_CONSTEXPR
void vector<_Tp, _Alloc>::
_M_assign_aux(_InputIterator __first, _InputIterator __last, std::input_iterator_tag)
{
    pointer __cur(this->_M_impl._M_start);
    // 将[__first, __last)元素赋值到[_M_start, _M_finish)区间
    for (; __first != __last && __cur != this->_M_impl._M_finish; ++__cur, (void)++__first)
        *__cur = *__first;
    // 当[__first, __last)元素个数小于等于[_M_start, _M_finish)时,删除__cur及其后剩余的数据
    if (__first == __last)
        _M_erase_at_end(__cur);
    // 当[__first, __last)元素个数大于[_M_start, _M_finish)时,需要继续[__first, __last)未赋值的元素填充到容器末端
    else
        _M_range_insert(end(), __first, __last, std::__iterator_category(__first));
}

// 当迭代器类型为forward、bidirectional或random-access调用
template<typename _Tp, typename _Alloc>
template<typename _ForwardIterator>
_GLIBCXX20_CONSTEXPR
void vector<_Tp, _Alloc>::
_M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag)
{
    const size_type __len = std::distance(__first, __last);

    // 当[__first, __last)元素个数大于原有容器容量,重新申请内存空间使用,并析构原容器内的所有元素、释放原容器内存空间
    if (__len > capacity())
    {
        _S_check_init_len(__len, _M_get_Tp_allocator());
        pointer __tmp(_M_allocate_and_copy(__len, __first, __last));
        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 = __tmp;
        this->_M_impl._M_finish = this->_M_impl._M_start + __len;
        this->_M_impl._M_end_of_storage = this->_M_impl._M_finish;
    }
    // 当[__first, __last)元素个数小于等于容器容量,且小于容器数据项个数时,
    // 将[__first, __last)元素赋值到容器内,并将剩余的旧数据项删除
    else if (size() >= __len)
        _M_erase_at_end(std::copy(__first, __last, this->_M_impl._M_start));
    // 当[__first, __last)元素个数小于等于容器容量,大于等于容器数据项个数时,
    // 先将[__first, __last)前size()个元素赋值到容器内,再将剩余未赋值的元素拷贝到容器末端
    else
    {
        _ForwardIterator __mid = __first;
        std::advance(__mid, size()); // 相当于__mid += size()
        std::copy(__first, __mid, this->_M_impl._M_start);
        const size_type __attribute__((__unused__)) __n = __len - size();
        _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
        this->_M_impl._M_finish = std::__uninitialized_copy_a(__mid, __last, this->_M_impl._M_finish,
            _M_get_Tp_allocator());
        _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
    }
}

assign操作将不再保留原容器的数据,而是完全根据assign函数指定的参数重新填充容器,原有数据被丢弃。

其中调用的子接口_M_range_insert()实现的细节如下:

// 定义于bits/stl_iterator.h
#if __cplusplus >= 201103L
#define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter) std::make_move_iterator(_Iter)
#define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) \
    std::__make_move_if_noexcept_iterator(_Iter)
#else
#define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter) (_Iter)
#define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) (_Iter)
#endif // C++11
// 定义于bits/stl_algobase.h
#if __cplusplus >= 201103L
#define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::move_backward(_Tp, _Up, _Vp)
#else
#define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::copy_backward(_Tp, _Up, _Vp)
#endif
// 仅当迭代器类型为input时调用当迭代器类型
template<typename _Tp, typename _Alloc>
template<typename _InputIterator>
_GLIBCXX20_CONSTEXPR
void vector<_Tp, _Alloc>::
_M_range_insert(iterator __pos, _InputIterator __first, _InputIterator __last, std::input_iterator_tag)
{
    // 如果是容器尾端插入,则遍历[__fitst,__last),依次插入到容器
    if (__pos == end())
    {
        for (; __first != __last; ++__first)
            insert(end(), *__first);
    }
    // 如果是在容器中间或首部插入,先构建临时的容器,再一次将[__fitst,__last)插入容器,
    // 此时只需对__pos后的元素做一次调整
    else if (__first != __last)
    {
        vector __tmp(__first, __last, _M_get_Tp_allocator());
        insert(__pos, _GLIBCXX_MAKE_MOVE_ITERATOR(__tmp.begin()), 
            _GLIBCXX_MAKE_MOVE_ITERATOR(__tmp.end()));
    }
}
// 当迭代器类型为forward、bidirectional或random-access调用
template<typename _Tp, typename _Alloc>
template<typename _ForwardIterator>
_GLIBCXX20_CONSTEXPR
void vector<_Tp, _Alloc>::
_M_range_insert(iterator __position, _ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag)
{
    if (__first != __last)
    {
        const size_type __n = std::distance(__first, __last);
        // 如果容器剩余空间足够插入
        if (size_type(this->_M_impl._M_end_of_storage - this->_M_impl._M_finish) >= __n)
        {
            const size_type __elems_after = end() - __position;
            pointer __old_finish(this->_M_impl._M_finish);
            // __position到容器末端end,剩余元素个数__elems_after大于待插入的元素个数__n
            if (__elems_after > __n)
            {
                _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
                // 先将容器最后__n个元素移动到容器末端,中间腾出__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());
                // 更新_M_finish指针
                this->_M_impl._M_finish += __n;
                _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
                // 移动或拷贝[__position, __old_finish - __n)到[__old_finish - (__elems_after - __n), __old_finish)
                _GLIBCXX_MOVE_BACKWARD3(__position.base(), __old_finish - __n, __old_finish);
                // 拷贝[__first, __last)到[__position, __position + __n)
                std::copy(__first, __last, __position);
            }
            // __position到容器末端end,剩余元素个数__elems_after小于等于待插入的元素个数__n
            else
            {
                _ForwardIterator __mid = __first;
                // 等同于__mid += elems_after
                std::advance(__mid, __elems_after);    
                _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
                // 先将[__first+elems_after, __last)区间的数据拷贝到容器末端
                std::__uninitialized_copy_a(__mid, __last, this->_M_impl._M_finish, _M_get_Tp_allocator());
                // 更新_M_finish指针
                this->_M_impl._M_finish += __n - __elems_after;
                _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);
                // 移动[__position, __old_finish)到容器末端
                std::__uninitialized_move_a(__position.base(), __old_finish,
                    this->_M_impl._M_finish, _M_get_Tp_allocator());
                // 更新_M_finish指针
                this->_M_impl._M_finish += __elems_after;
                _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
                // 拷贝[__first, __first+elems_after)到[__position, __position+elems_after)
                std::copy(__first, __mid, __position);
            }
        }
        // 容器剩余空间不足
        else
        {
            // 如果size() > __n,则容器新申请的空间大小为2倍size(), 否则为size()+__n
            const size_type __len = _M_check_len(__n, "vector::_M_range_insert");
            pointer __new_start(this->_M_allocate(__len));
            pointer __new_finish(__new_start);
            __try
            {
                // 移动[_M_start, __position)区间的数据到新的内存空间上
                __new_finish = std::__uninitialized_move_if_noexcept_a
                    (this->_M_impl._M_start, __position.base(), __new_start, _M_get_Tp_allocator());
                // 拷贝[__first, __last)区间的数据到容器末端
                __new_finish = std::__uninitialized_copy_a(__first, __last,
                    __new_finish, _M_get_Tp_allocator());
                // 移动[__position, _M_finish)区间的数据到容器末端
                __new_finish = std::__uninitialized_move_if_noexcept_a(__position.base(), 
                    this->_M_impl._M_finish, __new_finish, _M_get_Tp_allocator());
            }
            __catch(...)
            {
                // 若捕获异常,则析构所有元素,并释放申请的空间
                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;
        }
    }
}
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
size_type max_size() const _GLIBCXX_NOEXCEPT
{ return _S_max_size(_M_get_Tp_allocator()); }
_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;
}

_M_range_insert(iterator __position, _ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag)负责将区间[__first, last)的数据插入到__position位置。

有如下几种情况:

1)容器剩余空间足够插入,从插入位置__position到容器末端end()的数据个数大于待插入的数据个数,操作步骤示意图如下:

  假定,待插入个数__n = 2,__position到容器末端end()的数据个数__elems_after = 4

  步骤1,先将容器末端最后__n个元素移动至末尾__M_finish处;

  步骤2,将__position开始的__elems_after - _n个元素移动至原__M_finish前的__elems_after - _n个位置(std::move_back实现);

  步骤3,将待插入的__n个元素拷贝到__position开始处(步骤1和2已经将__position开始的__n个元素做了往后挪位的操作)。

img

2)容器剩余空间足够插入,从插入位置__position到容器末端end()的数据个数小于等于待插入的数据个数,操作步骤示意图如下:

  假定,待插入个数__n = 5,__position到容器末端end()的数据个数__elems_after = 2

  步骤1,将[__first + elems_after, __last)的数据拷贝到容器末端;

  步骤2,将__position开始到原容器末端(old_finish)的数据拷贝到现在的容器末端;

  步骤3,将[__first, __first + elems_after)的数据拷贝到__position开始的位置。

img

3)容器剩余空间不足插入新元素,操作步骤示意图如下:

  假定,待插入个数__n = 2,__position到容器末端end()的数据个数__elems_after = 2,剩余空间为1

  步骤1,为容器重新申请内存空间,并将[_M_start, __position)的元素移动到新内存空间地址上。申请大小根据容器的元素个数size和待插入元素个数__n决定,当size > __n时,为2倍size,否则为size+__n;

  步骤2,将待插入元素[__first, __last)插入到新容器末尾;

  步骤3,将原[__position, _M_finish)区间的元素插入到新容器末尾;

  步骤4,将原容器[__M_start, _M_finish)区间的元素析构,并释放原内存空间,同时将 __M_start、_M_finish、_M_end_of_storage指针指向新的内存地址。

img

5.5.2.2 push_back函数

push_back函数用于在容器末端插入元素,当容器未满时直接在末端插入,当容器满时调用_M_realloc_insert()重新申请内存空间并将原容器数据迁移,再于尾端插入元素。

_GLIBCXX20_CONSTEXPR
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);
}
#if __cplusplus >= 201103L
_GLIBCXX20_CONSTEXPR
void push_back(value_type&& __x)
{ emplace_back(std::move(__x)); }
template<typename... _Args>
#if __cplusplus > 201402L
    _GLIBCXX20_CONSTEXPR
    reference
#else
    void
#endif
    emplace_back(_Args&&... __args);
#endif

其中调用的子接口_M_realloc_insert()实现的细节如下:

#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
template<typename _Tp, typename _Alloc>
void vector<_Tp, _Alloc>::_M_realloc_insert(iterator __position, const _Tp& __x)
#endif
{
    // _M_check_len计算并返回新的内存空间大小
    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
    {
        // 在新内存空间的__position位置先构造 待插入的对象
        _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
        // _S_use_relocate判断_Alloc::value_type是否能移动插入(__is_move_insertable),std::__relocate_a调用是否会抛异常
        // 如果支持移动插入,std::__relocate_a不抛异常,则返回true,最终通过std::__relocate_a移动元素
        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());
        }
        // 否则使用std::__uninitialized_move_if_noexcept_a移动元素
        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;
}

_S_use_relocate()函数用来判断是否可使用std::__relocate_a进行数据构造,它判断_Alloc::value_type是否能移动插入(__is_move_insertable),std::__relocate_a调用是否会抛异常;

_S_relocate()当满足_S_use_relocate()为常量表达式时(理解应该是函数的constexpr属性生效,_S_use_relocate()在编译期间计算结果,作为常量表达式),调用std::__relocate_a。

std::__relocate_a函数的具体实现在<bits/stl_uninitialized.h>中,此处不予分析。

#if __cplusplus >= 201103L
static constexpr bool _S_nothrow_relocate(true_type)
{
    return noexcept(std::__relocate_a(std::declval<pointer>(),
        std::declval<pointer>(),
        std::declval<pointer>(),
        std::declval<_Tp_alloc_type&>()));
}
static constexpr bool _S_nothrow_relocate(false_type)
{ return false; }
static constexpr bool _S_use_relocate()
{
    // Instantiating std::__relocate_a might cause an error outside the
    // immediate context (in __relocate_object_a's noexcept-specifier),
    // so only do it if we know the type can be move-inserted into *this.
    return _S_nothrow_relocate(__is_move_insertable<_Tp_alloc_type>{});
}
static pointer _S_do_relocate(pointer __first, pointer __last, pointer __result,
    _Tp_alloc_type& __alloc, true_type) noexcept
{
    return std::__relocate_a(__first, __last, __result, __alloc);
}
static pointer _S_do_relocate(pointer, pointer, pointer __result,
    _Tp_alloc_type&, false_type) noexcept
{ return __result; }
static _GLIBCXX20_CONSTEXPR pointer
_S_relocate(pointer __first, pointer __last, pointer __result,
    _Tp_alloc_type& __alloc) noexcept
{
#if __cpp_if_constexpr
    // All callers have already checked _S_use_relocate() so just do it.
    return std::__relocate_a(__first, __last, __result, __alloc);
#else
    using __do_it = __bool_constant<_S_use_relocate()>;
    return _S_do_relocate(__first, __last, __result, __alloc, __do_it{});
#endif
}
#endif // C++11

子接口emplace_back()的处理类同void push_back(const value_type& __x)

// 在vector.tcc 定义
#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
5.5.2.3 insert函数

1)insert(const_iterator __position, const value_type& __x),在指定的__position位置插入元素__x

// 在vector.tcc 定义
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
insert(iterator __position, const value_type& __x)
#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);
        }
        // 插入位置不在容器末端,调用_M_insert_aux在指定位置插入元素
        else
        {
#if __cplusplus >= 201103L
            const auto __pos = begin() + (__position - cbegin());
            // __x 可以是当前容器的某个元素,所以这里不直接移动__x,而是移动__x的副本
            _Temporary_value __x_copy(this, __x);
            _M_insert_aux(__pos, std::move(__x_copy._M_val()));
#else
            _M_insert_aux(__position, __x);
#endif
        }
    // 容器已满,调用_M_realloc_insert重新申请内存并插入元素
    else
#if __cplusplus >= 201103L
        _M_realloc_insert(begin() + (__position - cbegin()), __x);
#else
        _M_realloc_insert(__position, __x);
#endif
    // 返回指向插入元素的迭代器
    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)
#else
template<typename _Tp, typename _Alloc>
void vector<_Tp, _Alloc>::
_M_insert_aux(iterator __position, const _Tp& __x)
#endif
{
    _GLIBCXX_ASAN_ANNOTATE_GROW(1);
    // 先拷贝构造最后一个元素,插入容器尾端,同时更新_M_finish指针
    _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
    _Tp __x_copy = __x;
#endif
    // [__position, _M_finish - 2)的所有元素往后挪一位,即移动到[__position + 1, _M_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
    *__position = std::forward<_Arg>(__arg);
#endif
}

_M_insert_aux操作步骤示意图如下:

img

2)iterator insert(const_iterator __position, value_type&& __x); 在指定的__position位置插入元素__x,__x为右值引用。该函数操作类同上面的常量左值引用参数的函数版本。

#if __cplusplus >= 201103L
_GLIBCXX20_CONSTEXPR
iterator insert(const_iterator __position, value_type&& __x)
{ return _M_insert_rval(__position, std::move(__x)); }
#endif
#if __cplusplus >= 201103L
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);
        }
        // 插入位置不在容器末端,调用_M_insert_aux在指定位置插入元素
        else
            _M_insert_aux(begin() + __n, std::move(__v));
    // 容器已满,调用_M_realloc_insert重新申请内存并插入元素
    else
        _M_realloc_insert(begin() + __n, std::move(__v));
    // 返回指向插入元素的迭代器
    return iterator(this->_M_impl._M_start + __n);
}
#endif

3)iterator insert(const_iterator __position, initializer_list<value_type> __l);在指定位置,插入初始化列表。

#if __cplusplus >= 201103L
iterator insert(const_iterator __position, initializer_list<value_type> __l)
{
    auto __offset = __position - cbegin();
    _M_range_insert(begin() + __offset, __l.begin(), __l.end(), std::random_access_iterator_tag());
    return begin() + __offset;
}
#endif

调用的方式形如:

insert(begin(), {1,2,3});

4)iterator insert(const_iterator __position, size_type __n, const value_type& __x);在指定位置,插入__n个值为__x的数据。

#if __cplusplus >= 201103L
_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;
}
#else
void insert(iterator __position, size_type __n, const value_type& __x)
{ _M_fill_insert(__position, __n, __x); }
#endif

C++98和C++11及以上版本,该函数的返回值不同,C++98返回void,C++11返回指向插入的第一个元素的迭代器。

其中子接口_M_fill_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)
        {
#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);
            // __position到容器末端end,剩余元素个数__elems_after大于待插入的元素个数__n
            if (__elems_after > __n)
            {
                _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
                // 先将容器最后__n个元素移动到容器末端,中间腾出__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());
                // 更新_M_finish指针
                this->_M_impl._M_finish += __n;
                _GLIBCXX_ASAN_ANNOTATE_GREW(__n);
                // 移动或拷贝[__position, __old_finish - __n)到[__old_finish - (__elems_after - __n), __old_finish)
                _GLIBCXX_MOVE_BACKWARD3(__position.base(), __old_finish - __n, __old_finish);
                // 以__x_copy填充[__position, __position + __n)
                std::fill(__position.base(), __position.base() + __n, __x_copy);
            }
            // __position到容器末端end,剩余元素个数__elems_after小于等于待插入的元素个数__n
            else
            {
                _GLIBCXX_ASAN_ANNOTATE_GROW(__n);
                // 先填充__n - __elems_after个数据到容器末端
                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);
                // 移动[__position, __old_finish)到容器末端
                std::__uninitialized_move_a(__position.base(), __old_finish, 
                    this->_M_impl._M_finish, _M_get_Tp_allocator());
                // 更新_M_finish指针
                this->_M_impl._M_finish += __elems_after;
                _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);
                // 填充[__position,__old_finish)
                std::fill(__position.base(), __old_finish, __x_copy);
            }
        }
        // 容器剩余空间不足
        else
        {
            // 如果size() > __n,则容器新申请的空间大小为2倍size(), 否则为size()+__n
            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
            {
                // 先在新的容器空间上填充[__position, __position + __n)
                std::__uninitialized_fill_n_a(__new_start + __elems_before,
                    __n, __x, _M_get_Tp_allocator());
                __new_finish = pointer();
                // 移动[_M_start, __position)区间的数据到新的内存空间上
                __new_finish = std::__uninitialized_move_if_noexcept_a
                    (this->_M_impl._M_start, __position.base(), __new_start, _M_get_Tp_allocator());
                __new_finish += __n;
                // 移动[__position, _M_finish)区间的数据到新的内存空间上
                __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;
        }
    }
}
// 类型为bool的特化版本
template<typename _Alloc>
_GLIBCXX20_CONSTEXPR
void vector<bool, _Alloc>::
_M_fill_insert(iterator __position, size_type __n, bool __x)
{
    if (__n == 0)
        return;
    // 剩余空间充足
    if (capacity() - size() >= __n)
    {
        std::copy_backward(__position, end(), this->_M_impl._M_finish + difference_type(__n));
        std::fill(__position, __position + difference_type(__n), __x);
        this->_M_impl._M_finish += difference_type(__n);
    }
    // 剩余空间不足
    else
    {
        const size_type __len = _M_check_len(__n, "vector<bool>::_M_fill_insert");
        _Bit_pointer __q = this->_M_allocate(__len);
        iterator __start(std::__addressof(*__q), 0);
        iterator __i = _M_copy_aligned(begin(), __position, __start);
        std::fill(__i, __i + difference_type(__n), __x);
        iterator __finish = std::copy(__position, end(), __i + difference_type(__n));
        this->_M_deallocate();
        this->_M_impl._M_end_of_storage = __q + _S_nword(__len);
        this->_M_impl._M_start = __start;
        this->_M_impl._M_finish = __finish;
    }
}

_M_fill_insert(iterator __position, size_type __n, const value_type& __x)用于在__position位置插入__n个值为__x的对象。当容器剩余空间充足时,插入步骤类同_M_range_insert;当容器剩余空间不足时,插入步骤类同_M_realloc_insert

5)iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last);在指定位置,插入[__first, __last)区间的数据。

#if __cplusplus >= 201103L
template<typename _InputIterator, typename = std::_RequireInputIter<_InputIterator>>
_GLIBCXX20_CONSTEXPR
iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last)
{
    difference_type __offset = __position - cbegin();
    _M_insert_dispatch(begin() + __offset, __first, __last, __false_type());
    // 返回指向插入位置的迭代器
    return begin() + __offset;
}
#else
template<typename _InputIterator>
void insert(iterator __position, _InputIterator __first, _InputIterator __last)
{
    // 检查_InputIterator类型是否为整型,非整型时,为迭代器
    typedef typename std::__is_integer<_InputIterator>::__type _Integral;
    _M_insert_dispatch(__position, __first, __last, _Integral());
}
#endif
// 模板参数为整型数据时调用
template<typename _Integer>
_GLIBCXX20_CONSTEXPR
void
_M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val, __true_type)
{ _M_fill_insert(__pos, __n, __val); }
// 模板参数为迭代器时调用
template<typename _InputIterator>
_GLIBCXX20_CONSTEXPR
void _M_insert_dispatch(iterator __pos, _InputIterator __first, _InputIterator __last, __false_type)
{
    _M_range_insert(__pos, __first, __last, std::__iterator_category(__first));
}

C++98和C++11及以上版本,该函数的返回值不同,C++98返回void,C++11返回指向插入的第一个元素的迭代器。

6. vector的重载运算符

6.1 移动赋值运算符重载和初始化列表赋值

#if __cplusplus >= 201103L
// 移动赋值运算符重载
_GLIBCXX20_CONSTEXPR vector& operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move())
{
    constexpr bool __move_storage = _Alloc_traits::_S_propagate_on_move_assign() 
        || _Alloc_traits::_S_always_equal();
    _M_move_assign(std::move(__x), __bool_constant<__move_storage>());
    return *this;
}
// 赋值运算符重载,支持初始化列表的赋值方式,如vector vec = {1, 2, 3};
_GLIBCXX20_CONSTEXPR vector& operator=(initializer_list<value_type> __l)
{
    this->_M_assign_aux(__l.begin(), __l.end(), random_access_iterator_tag());
    return *this;
}
// 分配器支持移动赋值
_GLIBCXX20_CONSTEXPR
void _M_move_assign(vector&& __x, true_type) noexcept
{
    // 交换两个容器指针
    vector __tmp(get_allocator());
    this->_M_impl._M_swap_data(__x._M_impl);
    __tmp._M_impl._M_swap_data(__x._M_impl);
    std::__alloc_on_move(_M_get_Tp_allocator(), __x._M_get_Tp_allocator());
}
_GLIBCXX20_CONSTEXPR
void _M_move_assign(vector&& __x, false_type)
{
    // 分配器支持移动赋值
    if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator())
        _M_move_assign(std::move(__x), true_type());
    else
    {
        // 分配器不支持移动赋值,则调用_M_assign_aux赋值新容器,直接移动容器内的每个元素
        this->_M_assign_aux(std::make_move_iterator(__x.begin()),
            std::make_move_iterator(__x.end()), std::random_access_iterator_tag());
        __x.clear();
    }
}
#endif

6.2 赋值运算符重载

template<typename _Tp, typename _Alloc>
_GLIBCXX20_CONSTEXPR
vector<_Tp, _Alloc>& vector<_Tp, _Alloc>::
operator=(const vector<_Tp, _Alloc>& __x)
{
    if (std::__addressof(__x) != this)
    {
        _GLIBCXX_ASAN_ANNOTATE_REINIT;
#if __cplusplus >= 201103L
        if (_Alloc_traits::_S_propagate_on_copy_assign())
        {
            // 分配器不支持移动赋值,即旧分配器申请的内存不能由新分配器来释放,
            // 这种情况需要析构原容器内的数据对象,并释放内存空间。
            if (!_Alloc_traits::_S_always_equal()
                && _M_get_Tp_allocator() != __x._M_get_Tp_allocator())
            {
                // replacement allocator cannot free existing storage
                this->clear();
                _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage
                    - this->_M_impl._M_start);
                this->_M_impl._M_start = nullptr;
                this->_M_impl._M_finish = nullptr;
                this->_M_impl._M_end_of_storage = nullptr;
            }
            std::__alloc_on_copy(_M_get_Tp_allocator(), __x._M_get_Tp_allocator());
        }
#endif
        const size_type __xlen = __x.size();
        // 新容器容量大于原容器容量,重新申请内存并拷贝新容器数据,析构原容器对象,并释放原容器内存空间。
        if (__xlen > capacity())
        {
            pointer __tmp = _M_allocate_and_copy(__xlen, __x.begin(), __x.end());
            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 = __tmp;
            this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __xlen;
        }
        // 原容器数据个数大于等于新容器数据个数,将新容器的数据拷贝至原容器首部,并析构尾部多余的旧数据对象
        else if (size() >= __xlen)
        {
            std::_Destroy(std::copy(__x.begin(), __x.end(), begin()), end(), _M_get_Tp_allocator());
        }
        // 原容器数据个数小于新容器数据个数,先拷贝size()个元素到新容器,再拷贝构造剩余的数据。
        else
        {
            std::copy(__x._M_impl._M_start, __x._M_impl._M_start + size(), this->_M_impl._M_start);
            std::__uninitialized_copy_a(__x._M_impl._M_start + size(), 
                __x._M_impl._M_finish, this->_M_impl._M_finish, _M_get_Tp_allocator());
        }
        this->_M_impl._M_finish = this->_M_impl._M_start + __xlen;
    }
    return *this;
}

6.3 []运算符重载

// []运算符重载,使vector支持随机存取,返回容器第__n个对象的引用
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reference operator[](size_type __n) _GLIBCXX_NOEXCEPT
{
    __glibcxx_requires_subscript(__n);
    return *(this->_M_impl._M_start + __n);
}
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
const_reference operator[](size_type __n) const _GLIBCXX_NOEXCEPT
{
    __glibcxx_requires_subscript(__n);
    return *(this->_M_impl._M_start + __n);
}
posted @   流翎  阅读(587)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示