STL vector
STL2.91源码地址: https://github.com/lewischeng-ms/sgi-stl
侯捷老师用的是 2.91,不同版本的STL差异很大,靠后版本的STL用了太多typedef以及继承关系,导致可读性很差。
本文参考博客: https://blog.csdn.net/weixin_45389639/article/details/121618243
vector 源码
// vector源码
template<class T,class Alloc=alloc>
class vector
{
public:typedef T value_type;typedef value_type* iterator;typedef value_type& reference;typedef size_t size_type;
protected:iterator start;iterator finish;iterator end_of_storage;
public:iterator begin(){return start;}iterator end(){return finish;}size_type size()const{return (size_type)end_of_storage-begin();}bool empty()const{return begin()==end();}reference operator[](size_type n){return *(begin()+n);}reference front(){return *begin();}reference back(){return *(end()-1);}...
};
vector源码分析
vector中定义了三个指针: start 、finish 、 end_of_storage
sizeof(vector): 三个指针的大小
vector扩容:空间两倍增长
vector容器的迭代器start指向第一个元素,finish指向最后一个元素的下一个元素,满足了前闭后开特性,end_of_storage是vector的容量。vector在使用上是连续的,在实现上也是连续的,所以迭代器采用non-class类型。
// vector源码
template<class T,class Alloc=alloc>
class vector
{
public:typedef T value_type;typedef value_type* iterator;typedef value_type& reference;typedef size_t size_type;
protected:iterator start;iterator finish;iterator end_of_storage;
public:iterator begin(){return start;}iterator end(){return finish;}size_type size()const{return (size_type)end_of_storage-begin();}bool empty()const{return begin()==end();}reference operator[](size_type n){return *(begin()+n);}reference front(){return *begin();}reference back(){return *(end()-1);}...
};
vector.push_back()的方法,首先会判断end_of_storage是不是满了,满了的话就会扩容2倍再进行添加元素。注意:扩充的过程重并不是在原有空间后面追加容量,而是重新申请一块连续的内存空间,将原有的数据拷贝到新空间中,再释放原来空间中内存。所以扩充之后,原有的迭代器将会失效!
void push_back(const T& x) {if (finish != end_of_storage) {construct(finish, x);++finish;}elseinsert_aux(end(), x);}
insert_aux是vector容器用来在内部任意位置插入元素,内存不足的情况下会扩容。
template<class T, class Alloc>
void vector<T, Alloc>::insert_ux(iterator position, const T &x) {if (finish != end_of_storage) { // 尚有备用空间,则将插入点后元素后移一位并插入元素construct(finish, *(finish - 1)); // 以vector最后一个元素值为新节点的初值++finish;T x_copy = x;copy_backward(position, finish - 2, finish - 1);*position = x_copy;} else {// 已无备用空间,则先扩容,再插入const size_type old_size = size();const size_type len = old_size != 0 ?: 2 * old_size:1; // 扩容后长度为原长度的两倍iterator new_start = data_allocator::allocate(len);iterator new_finish = new_start;try {new_finish = uninitialized_copy(start, position, new_start); // 拷贝插入点前的元素construct(new_finish, x); // 插入新元素并调整水位++new_finish;//这个辅助还是不止被push_back调用,其他函数(insert)也会调用。 insert插入需要扩充数据,会有安插点之前和安插点之后//需要将安插点之后的元素也拷贝过来new_finish = uninitialized_copy(position, finish, new_finish); // 拷贝插入点后的元素}catch (...) {// 插入失败则回滚,释放内存并抛出错误destroy(new_start, new_finish) :data_allocator::deallocate(new_start, len);throw;}// 释放原容器所占内存destroy(begin(), end());deallocate();// 调整迭代器start = new_start;finish = new_finish;end_of_storage = new_start + len;}
};
vector迭代器
列表的迭代器设置为class,因为列表的节点都是分离的
vector用指针就可以当作迭代器
class vector {
public:typedef T value_type;typedef const value_type* const_pointer;typedef value_type* iterator;};-------------------------------------------------//使用迭代器vector<int> vec;vecto<int>::iterator it = vec.begin();
算法使用vec的迭代器,需要知道迭代器的5个参数会将value_type* iterator迭代器丢给traits,
traits使用指针偏特化的版本 iterator_traits<T>*、
这一部分需要对萃取有一些了解: https://editor.csdn.net/md/?articleId=138084134