STL:一篇带你搞懂vector
- vector底层实现
-
- 1.constructor与destructor
- 2.迭代
- 3.capacity
- 4.modifier
-
- [4.1 push_back](#4.1 push_back)
- [4.4 pop_back](#4.4 pop_back)
- [4.3 insert](#4.3 insert)
- [4.4 erase](#4.4 erase)
- [5.access ](#5.access [ ])
vector底层实现
1.constructor与destructor
vector的构造包括默认构造,普通的构造函数、拷贝构造以及使用迭代区间进行构造。下面我们逐一分析这几种构造方式。
cpp
vector()
{
_start = _finish = nullptr;
_end_of_storage = nullptr;
}
vector(int n, const T& val = T())
{
for (int i = 0; i < n; i++)
{
push_back(val);
}
}
template<class Inputiterator>
vector(Inputiterator first, Inputiterator last)
{
Inputiterator begin = first;
while (begin != last)
{
push_back(*begin);
begin++;
}
}
vector(const vector<T>& v)
{
for (auto& e : v)
{
push_back(e);
}
}
void swap(vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_storage, v._end_of_storage);
}
vector<T>& operator=(vector<T> v)//这里专门没有使用引用
{
swap(v);
return *this;
}
~vector()
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
这里要着重说一下:T(),它对于内置类型,自动初始化为0;对于自定义类型,会调用自己的默认构造。
赋值操作 :采用现代写法,交换地址,同时重载函数的参数并没有使用引用,这样可以在调用完重载函数,自动实现对资源的释放。
2.迭代
vector的底层本身就是数组,所以它迭代器的底层就是指针,我们可以使用三个迭代器(start,finish,end_of_storage)来控制这个数组(顺序表)。
cpp
template<class T>
class vector
{
public:
typedef T* iterator;
typedef const T* const_iterator;
///////////////////////////////////////////////
//迭代器
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
const_iterator begin()const
{
return _start;
}
const_iterator end()const
{
return _finish;
}
private:
iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
}
3.capacity
cpp
size_t size()const
{
return _finish - _start;
}
size_t capacity()const
{
return _end_of_storage - _start;
}
void reserve(size_t n)
{
if (n > capacity())
{
size_t old_size = size();
T* tmp = new T[n];
//这里如果是自定义类型,就是错误的,因为这里仅仅是浅拷贝
/*memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;*/
//这里要进行拷贝构造
if (_start)
{
for (size_t i = 0; i < n; i++)
{
tmp[i] = _start[i];
}
delete _start;
}
_start = tmp;
_finish = _start + old_size;
_end_of_storage = _start + n;
}
void resize(size_t n, const T& val = T())
{
if (n > capacity())
{
reserve(n);
}
for (size_t i = size(); i < n; i++)
{
_start[i] = val;
}
_finish = _start + n;
}
vector的扩容问题:vs(STL为pj版本)以1.5倍进行扩容,g++(STL为SGI版本)以2倍扩容。
memcpy问题:memcpy是对内存中的内容进行一字节一字节拷贝,如果是内置类型,没有任何问题;如果是自定义类型,这就是浅拷贝,释放空间时也会导致拷贝的元素释放,进而报错。

4.modifier
4.1 push_back
cpp
void push_back(const T& val)
{
if (size() == capacity())
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = val;
_finish++;
}
4.4 pop_back
cpp
void pop_back()
{
assert(_start != _finish);
_finish--;
}
4.3 insert
cpp
iterator insert(iterator pos, const T& val)
{
assert(pos >= _start);
assert(pos <= _finish);
if (size() == capacity())
{
size_t n = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + n;//防止迭代器失效
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *(end);
end--;
}
*pos = val;
_finish++;
return pos;
}
4.4 erase
cpp
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator begin = pos + 1;
while (begin < _finish)
{
*(begin - 1) = *(begin);
begin++;
}
_finish--;
return pos;
}
迭代器失效:
1.对于 insert 来说,如果容量满了的话,那么就需要扩容,原来的pos就会被释放掉,进而导致访问时就是随机数。
2.对于 erase 来说,pos原本指向的值已经被后一个值覆盖,因此返回的pos是指向下一个值的,如果删除的是末尾的值话,pos指向的值就已经越界,不能进行解引用或自增操作,因为已经越界。
3.对于底层有内存的改变,pos位置都有可能出现迭代器失效问题。

解决方法:更新迭代器。
5.access
cpp
T& operator[](size_t pos)
{
assert(pos < size());
return _start[pos];
}
const T& operator[](size_t pos)const
{
assert(pos < size());
return _start[pos];
}
---------------------------------------------------------------------
完结啦🎇