1.前言
上一篇我们讲到了string的底层实现,那么今天我们就深究一下vector的底吧!vector其实看起来比string简单得多,如果是int类型的vector,不就是我们之前学的顺序表吗?但是呢,直到我们深究它的底层,其实还是有很多值得我们学习的地方呀,我们要完全实现vector,有很多细节需要注意,这样也更加方便我们对于使用vector更加熟练。
2.代码实现
还是一样,代码和注释都放在下面啦,同学们细品哦!
#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
#include<algorithm>
namespace bit
{
template<class T> //创建模板参数
class vector
{
public:
//迭代器
typedef T* iterator;
iterator begin()
{
return _start;
}
iterator end()
{
return _finish;
}
//强制生成默认构造
vector() = default;
//拷贝构造
//v2(v1)
vector(const vector<T>& v)
{
//先开空间
reserve(v.capacity());
//拷贝数据
for (auto e : v)
{
push_back(e);
}
}
//交换函数
void swap(const vector<T>& v)
{
std::swap(_start, v._start);
std::swap(_finish, v._finish);
std::swap(_end_of_stroage, v._end_of_stroage);
}
//赋值拷贝
//v1 = v3
vector<T>& operator=(const vector<T>& v)
{
//这里相当于 this->swap(v);也就是this和v交换,这里可以省略this,是一个意思
swap(v);
return *this;
}
//迭代器区间初始化
template<class InputIterator> //目的:支持任意类型的迭代器区间初始化
vector(InputIterator first, InputIterator last)
{
while (first != last)
{
push_back(*first);
++first;
}
}
//用n个value构造
vector(size_t n, const T& val = T()) //这样给缺省值的意思是给默认构造的匿名对象,对于内置类型也支持,这是C++做出的升级
{
for(size_t i = 0;i < n;i++)
{
push_back(val);
}
}
//initializer_list初始化(支持花括号的初始化)
vector(initializer_list<T> li)
{
reserve(li.size());
for (auto e : li)
{
push_back(e);
}
}
//析构
~vector()
{
//start不为空就析构,不然没必要
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}
//扩容
void reserve(size_t n)
{
if (n > capacity())
{
size_t oldsize = size(); //存储一份旧的size
T* tmp = new T[n];
//如果旧start为空,就不需要拷贝旧数据了
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size()); //缺点:memcpy对任意类型都是浅拷贝
delete[] _start;
}
//新的
_start = tmp;
//更新指针
_finish = _start + oldsize;
_end_of_storage = _start + n;
}
}
//容量函数
size_t capacity()
{
return _end_of_storage - _start;
}
//有效数据函数
size_t size()
{
return _finish - _start;
}
// []
T& operator[](size_t i)
{
assert(i < size());
return _start[i];
}
//尾插
void push_back(const T& x)
{
//如果满了就扩容
if (_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newcapacity);
}
*_finish = x;
++_finish;
}
//尾删
void pop_back()
{
assert(size() > 0);
--_finish;
}
//插入
iterator insert(iterator pos, const T& x)
{
//满了就扩容
if (_finish == _end_of_storage)
{
//为了防止reserve注释中的内容,所以要先记录pos在原来空间中的位置
size_t len = pos - _start;
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
reserve(newcapacity); //更新了_start,_finish,_end_of_storage,唯独pos还停留在原地
//更新pos,不扩容就不要更新pos
pos = _start + len;
}
//移位(由于pos是iterator的类型,所以必须要用iterator给其挪位)
iterator end = _finish - 1;
while (end >= pos)
{
*(end + 1) = *end; //前面是把int* typedef成了iterator,所以可以用解引用的方式访问,但是库里的iterator本质不一定是指针
end--;
}
*pos = x;
_finish++;
return pos;
}
//删除
void erase(iterator pos) //注意erase在库里面返回的是iterator
{
assert(pos <= _finish);
iterator it = pos + 1;
while (it != _finish)
{
*(it - 1) = *it;
it++;
}
--_finish;
}
private:
//为了保持和库里的一致,我们定义成这样
iterator _start = nullptr; //相当于数组指针
iterator _finish = nullptr; //相当于_size
iterator _end_of_storage = nullptr; //相当于_capacity
};
}
怎么样,vector是不是也有很多细节呢?你都注意到了嘛?相信你学到了很多哦,咱们下期见咯!