作为STL中的顺序类容器(vector,deque,list,forward_list,array)之一,通常被当作是c++的数组来使用,但其要比c的数组灵活的多,空间不够时能够自动扩展,并且占用的是堆内存。
c++20之后 vector中的 push_back 方法通过调用 emplace_back 方法实现。建议使用emplace_back来代替push_back,省去了构造一个临时变量再赋值的操作,而是直接在数组尾部进行构造新对象。
1、vector 迭代器
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;
可见vector 的迭代器基本就是指针
2、vector 数据结构 vector是连续空间,有三个指针指向了不同位置
struct _Vector_impl_data {
pointer _M_start; //指向使用空间的头
pointer _M_finish; //指向使用空间的尾
pointer _M_end_of_storage; //指向剩余空间的尾
};
这三个指针分别可以对vector 的头、尾元素、容器体积进行试算
3、vector 元素操作 pop_back
//pop元素
void pop_back()
{
__glibcxx_requires_nonempty();
--this->_M_impl._M_finish;
_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish);
_GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
}
弹出尾部元素,并调整容器大小
emplace
iterator emplace(const_iterator __position, _Args&&... __args)
{ return _M_emplace_aux(__position, std::forward<_Args>(__args)...); }
新增加的插入元素的方法,第一个参数传入迭代器,第二个参数传入需要插入的新值,新值会传入迭代器对应元素前面。
insert 在指定位置插入已存在的对象,当对象已经存在或需要需要同时插入多个对象时会使用。适合简单的不追求性能的场景。
iterator insert(const_iterator __position, value_type&& __x)
{ return _M_insert_rval(__position, std::move(__x)); }
4、vector 的API实现
默认构造函数: vector arr; 这种情况下vector大小为零,为了节约内存空间,vector 不会主动申请内存、创建缓冲区
构造函数: 注意vector arr(100,0);和vector arr(100);两者在size和capicity没有区别,都会输出size:100,capacity:100
拷贝构造函数: 先申请目标对象同等大小的内存,再将目标容器内的所有值拷贝过去
vector(const vector<_Tp, _Alloc>& __x)
: _Base(__x.size(), __x.get_allocator())
{ _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }
从迭代器构造 vector:
// Check whether it's an integral type. If so, it's not an iterator.
template <class _InputIterator>
// 通用构造函数,接受两个迭代器
vector(_InputIterator __first, _InputIterator __last,
const allocator_type& __a = allocator_type()) : _Base(__a) {
// 判断模版参数是否是整数类型
typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
// 根据是否是整数调用不同的辅助函数
_M_initialize_aux(__first, __last, _Integral());
}
// 当参数是整数类型时 __true_type
template <class _Integer>
void _M_initialize_aux(_Integer __n, _Integer __value, __true_type) {
_M_start = _M_allocate(__n); // 分配n个空间
_M_end_of_storage = _M_start + __n;
_M_finish = uninitialized_fill_n(_M_start, __n, __value); // 用 __value填充
}
比如
vector<int> a(100, 0);
vector<int> b(a.begin(), a.begin() + 10);
a是调用整型构造 而b是调用迭代器构造
析构函数:
当生命周期结束,对象即将被回收时,首先调用vector::~vector 然后调用_Vector_base::~_Vector_base释放已申请的内存
其他知识点: begin: 返回左边界迭代器
end:返回右虚边界迭代器
rbegin:返回右虚边界的反向迭代器
rend:返回数据左边界迭代器
size:返回end()-begin()
max_size:返回size_type类型的最大数
capacity:返回_M_end_of_storage-begin() 即缓冲区能够容纳的元素个数
swap:调换两个vector中的内容,只需要交换vector内部数据结构中的三个指针即可
insert:在任意位置插入任意数量个元素
pop_back:销毁尾部元素
erase:销毁指定区间内容
resize:两种情况,新size大于当前size,则插入new_size-old_size个0值;new_size小于old_size时,则对old_size-new_size个元素执行erase操作,但resize不会释放缓冲区上的可用内存
reserve:申请新内存
operator=:重构后的赋值运算符
三种情况:
b.size > a.capacity 时, a先执行_M_allocate_and_copy 申请并初始化新缓冲区,再执行_M_deallocate释放旧缓冲区
b.size < a.size 直接复制b到a, 并销毁a中多余对象
a.size < b.size < a.capacity 先复制b中前a.size个元素到a中,然后执行unitialiized_copy复制b中后b.size-a.size个元素到a中
assign(n, val) 实现也分三种情况
n > a.capacity, 构造新vector(假设为tmp), 并执行a.swap(tmp)
a.size < n < a.capacity, 同operator=
n < a.size, 同operator=