1概述
c++提供了array, STL再提供vector、list、deque、stack、queue、priority_queue
vector和array区别
array是静态的空间,不能原地扩充, 一旦配置好了就不能变了,要是不够了,就得我们自己弄,再新建一个、复制、释放,好麻烦的
vector就是STL全包了,不用我们动手了
两倍扩充, 找不到两倍就结束了
#include<vectoe> -> #include<stl_vector.h>
2 迭代器
空间连续 类普通指针 RAI
连续的不用太复杂, 指针就可以了
3 数据结构
start、finish、end_of_storage
容器是前闭后开, finish指向超尾
连续空间支持[]
```C++
struct _Vector_impl
: public _Tp_alloc_type
{
pointer _M_start;
pointer _M_finish;
pointer _M_end_of_storage;
```
size() capacity()
新增元素时,一般扩充两倍, 不同编译器不同
扩充: 重新申请、复制、释放
4 构造和内存管理
```C++
vector(size_type __n, const value_type& __value,
const allocator_type& __a = allocator_type())
: _Base(__n, __a)
{ _M_fill_initialize(__n, __value); }
void
_M_fill_initialize(size_type __n, const value_type& __value) // fill_initialize(n, value);
{
this->_M_impl._M_finish = std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value,
_M_get_Tp_allocator());
}//我看源码就是一直调用函数,最终调用的是construct
```
5 vector操作 push_back、pop_back、emplace_back、erase、clear、insert
5.1 push_back()
```C++
void
push_back(const value_type& __x)
{
if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) //finish != end_of_storage
{
_GLIBCXX_ASAN_ANNOTATE_GROW(1);
_Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
__x); //在finish处构造
++this->_M_impl._M_finish;//finish++
_GLIBCXX_ASAN_ANNOTATE_GREW(1);
}
else
_M_realloc_insert(end(), __x); //没有空间了
}
```
```C++
template<typename _Tp, typename _Alloc>
void
vector<_Tp, _Alloc>::
_M_realloc_insert(iterator __position, const _Tp& __x) //end(), x
#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();
__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;
}
_GLIBCXX_ASAN_ANNOTATE_REINIT;
std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());//析构原vector
_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;
}
```
空间重新配置后,原来的迭代器都失效了
5.2 pop_back()
```C++
void
pop_back() _GLIBCXX_NOEXCEPT
{
__glibcxx_requires_nonempty();
--this->_M_impl._M_finish; //--finish
_Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish); //析构超尾元素
_GLIBCXX_ASAN_ANNOTATE_SHRINK(1);
}
```
5.3 erase()
```C++
erase(iterator __first, iterator __last)
{ return _M_erase(__first, __last);
template<typename _Alloc>
typename vector<bool, _Alloc>::iterator
vector<bool, _Alloc>::
_M_erase(iterator __first, iterator __last)
{
if (__first != __last)
_M_erase_at_end(std::copy(__last, end(), __first)); //复制last到finish到一个新的空间里并返回到__first上
return __first;
}
```
5.4 insert()
代码很长,我就不放了, 见侯老师的书或者看源码也行
因为是立着画的, 所以画的不太好
还有个问题,我觉得第一个old_finish和finish一样的话两次复制不就覆盖掉了吗? 没明白
-
第一种情况: 备用空间够用且插入位置后面的元素大于插入元素
-
第二种情况: 备用空间够用且插入位置后面的元素小于插入元素
-
第三种情况: 备用空间不够用
侯老师视频补充知识点
未指定空间大小为0
move()