目录
大致框架
namespace zbw
{
template <class T>
class vector
{
public:
typedef T* iterator;
private:
iterator _start;
iterator _finish;
iterator _end_of_storage;
};
}
1.构造函数
(1)无参构造
vector()
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{}
(2)带参构造函数
vector(size_t n,const T& val = T())//const延长匿名对象的生命周期
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
reverse(n);
for (int i = 0; i < n; i++)
{
push_back(val);
}
}
(3)用迭代器构造初始化函数
tmplete <class InputIterator>
vector(InputIterator first,InputIterator last)
:_start(nullptr)
, _finish(nullptr)
, _end_of_storage(nullptr)
{
while (first != last)
{
push_back(*first);
first++;
}
}
使用迭代器模板,就可以传任意类型的迭代器,否则只能使用vector的迭代器
起名为InputIterator,是因为函数模板的模板参数要传迭代器区间时,是存在命名规范的
InputIterator这种迭代器所指的对象为“只读”,不允许外界更改
(4)拷贝构造函数
传统写法
vector(const vector<T>& v)//v2(v1)
{
_start = new T[v.capacity()];
_finish = _start + v._size();
_end_of_storage = _start + v._capacity;
memcpy(_start, v._start, v.size() * sizeof(T));
}
开一块和v1一样大的空间,再把v1的数据拷贝到新空间里去
现代写法
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(const vector<T>& v)//v2(v1)
{
vector<T> tmp(v.begin(), v.end());
swap(tmp);
}
利用迭代器初始化的构造函数,用v1创造一个临时变量tmp,再将v2与tmp交换,tmp出了作用域就调用析构函数销毁
2.operator=
现代写法
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=(const vector<T> v)//v3 = v1
{
swap(v);
return *this;
}
利用传值传参拷贝构造v(此时v就是v1),再将v3与v1交换,v是临时对象除了作用域会调用析构函数销毁
3.operator[]
T& operator[](size_t i)
{
assert(i < size());
return _start[i];//_start的类型是T*,T是模板,所返回值是T&
}
const T& operator[](size_t i) const
{
assert(i < size());
return _start[i];
}
const版本适合const类型的对象传参,且只能读不能写
4.size()
size_t size() const
{
return _finish - _start;
}
5.capacity()
size_t capacity() const
{
return _end_of_storage - _size;
}
6.push_back
首先判断容量是否足够,不够就进行增容
然后如果是空数组,就直接在_finish的位置上插入
如果数组不为空且容量不足,就将数据拷贝到扩容后的新空间,再在_finish的位置插入
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
T* tmp = T[newcapacity];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
}
*_finish = x;
_finish++;
}
但是代码会崩溃,因为_finish和_end_of_storage无参构造之后是空指针,所以我们需要借助tmp算出_finish和_end_of_storage
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
T* tmp = T[newcapacity];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
_finish = _start + size();//算出_finish的位置
_end_of_storage = _start + newcapacity;//算出_end_of_storage的位置
}
*_finish = x;
_finish++;
}
但是又因为我们实现的size()是_finish - _start,所以_finish=_start+ _finishi - _start = _finish
相互抵消之后,_finish永远是个空指针
最终版本(提前准备好size,再去更新_start)
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
T* tmp = T[newcapacity];
size_t sz = size();//提前算出size
if (_start)//等于空则不需要拷贝
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + newcapacity;
}
*_finish = x;
_finish++;
}
7.reserve
void reserve(size_t n)
{
if (n > capacity())
{
size_t sz = size();
T* tmp = new T[n];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
_finish = _start + sz;
_end_of_storage = _start + n;
}
}
如果输入的数量大于capacity就扩容
然后我们可以将reserve复用到push_back里
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
*_finish = x;
_finish++;
}
8.迭代器(vector的原生指针)
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;
}
9.resize
void resize(size_t n,const T& val = T())
{
if (n < size())
{
_finish = _start + n;
}
else
{
if (n > capacity())
{
reserve(n);
}
while (_finish != _start + n)
{
*_finish = val;
_finish++;
}
}
}
val的缺省值不能=0,因为val不一定是整形,还可能是其他类型
所以就用匿名对象,并用const延长它的生命周期
10.pop_back
void pop_back()
{
assert(_finish > _start)
_finish--;
}
当_finish == _start时,就没有数据了
11.insert
void insert(iterator pos,const T& x)
{
assert(pos <= _finish)
assert(pos >= _start)
if (_finish == _end_of_storage)
{
reserve(capacity() == 0 ? 4 : capacity() * 2);
}
iterator end = _finish - 1;
while (end >= pos)
{
*(end - 1) = *end;
end--;
}
*pos = x;
_finish++;
}
但是会出现迭代器失效的问题
在插入时进行若进行扩容,会开辟一个新空间,这时_start和_finish都改变了指向
当原空间被释放后,pos指向了一个被释放的空间,变成了野指针
解法:
可以提前算好pos与_start之间的距离
但是我们调用insert函数时,传的是实参
vector<int>::iterator it = find(v.begin(), v.end(), 2); if (it != end()) { v.insert(it, 12); }
如果之后我们还要使用这个it,那么这个it就是失效了
因为我们写的insert的实现是传值返回,形参的改变不影响实参
如果insert中发生了扩容,就会导致it指向空间被释放,让it成为一个野指针,这也叫做叫做迭代器失效
解法:
用一个返回值接收pos
iterator insert(iterator pos,const T& x) { assert(pos <= _finish) assert(pos >= _start) if (_finish == _end_of_storage) { //扩容会导致pos的失效,扩容前需要更新一下pos size_t len = pos - _start; reserve(capacity() == 0 ? 4 : capacity() * 2); pos = _start + len; } iterator end = _finish - 1; while (end >= pos) { *(end - 1) = *end; end--; } *pos = x; _finish++; return pos; }
调用insert时
vector<int>::iterator it = find(v.begin(), v.end(), 2); if (it != end()) { it = v.insert(it, 12); }
若将v.insert(it,12)改为v.insert(v.begin(),12)
并iterator insert(iterator pos,const T& x)改为iterator insert(iterator& pos, const T& x)
这样做是不行的
因为begin()是传值返回,返回的是临时变量,具有常性,不能直接传给引用
12.erase
void erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator begin = pos + 1;
while (begin < _finish)
{
*(begin - 1) = *begin;
++begin;
}
--_finish;
}
vector<int>::iterator it = v.begin; while(it != v.end) { if(*it % 2 == 0)//删除所有偶数 { v.erase(it); } it++; }
若我们要求删除数据1234中的所有偶数,代码就会出错
因为如果最后一个数是偶数,会导致erase之后it再次++,这会导致it错过_finish,导致越界
erase(it)后,it指向位置的意义就改变了,如果是连续的偶数,会导致后一个偶数没有被判断,也没有被删掉
erase(it)后it的意义改变了,本质上就是it失效了
iterator erase(iterator pos)
{
assert(pos >= _start);
assert(pos < _finish);
iterator begin = pos + 1;
while (begin < _finish)
{
*(begin - 1) = *begin;
++begin;
}
--_finish;
return pos;
}
对erase增加一个返回值,返回删除后pos的位置
vector<int>::iterator it = v.begin;
while(it != v.end)
{
if(*it % 2 == 0)//删除所有偶数
{
it = v.erase(it);
}
else
{
it++;
}
}
13.memcpy替换为深拷贝
之前实现的push_back
void push_back(const T& x)
{
if (_finish == _end_of_storage)
{
size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
T* tmp = T[newcapacity];
if (_start)
{
memcpy(tmp, _start, sizeof(T) * size());
delete[] _start;
}
_start = tmp;
}
*_finish = x;
_finish++;
}
我们写的push_back拷贝用的是memcpy,对于内置类型,tmp出了作用域也不用处理,但对于自定义类型,tmp除了作用域还要被析构一次,一个空间总共析构了两次,程序崩溃
解决方法:
不用memcpy进行浅拷贝,而是进行深拷贝
我们直接更改reserve,再在push_back里复用
void reserve(size_t n) { if (n > capacity()) { size_t sz = size(); T* tmp = new T[n]; if (_start) { for (size_t i = 0; i < sz; i++) { tmp[i] = _start[i]; } delete[] _start; } _start = tmp; _finish = _start + sz; _end_of_storage = _start + n; } }
如果T是自定义类型,拷贝调用的是T的深拷贝赋值
void push_back(const T&x) { if (_finish == _end_of_storage) { reserve(capacity() == 0 ? 4 : capacity() * 2); } *_finish = x; ++_finish; }