目录
成员变量设计为三个迭代器,分别是:_start、_finish、_endofstorage。此设计原理参考STL源码。_start与_finish之间是存储有效元素的;_start与_endofstorage之间表容器的容量。

- iterator _start;
- iterator _finish;
- iterator _endofstorage;
使用指针的方式实现迭代器,同时需要兼顾 const 对象和 const 迭代器。
- 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;
- }
- size_t size()
- {
- return _finish - _start;
- }
- size_t capacity()
- {
- return _endofstorage - _start;
- }
- void clear()
- {
- _finish = _start;
- }
- bool empty()
- {
- return _finish == _start;
- }
reserve如果涉及到扩容,统一采用异地扩容的方式。当参数小于当前容量时不作处理。
- void reserve(const size_t& n)
- {
- if (n > capacity())
- {
- T* tmp = new T[n];
- assert(tmp); //检查是否成功开辟
- int oldsize = _finish - _start;
-
- if (_start) //如果_start不为空需要拷贝数据
- {
- memcpy(tmp, _start, sizeof(T) * oldsize);
- delete[] _start; //释放旧空间
- }
-
- //异地扩容,更新迭代器
- _start = tmp;
- _finish = _start + oldsize;
- _endofstorage = _start + n;
- }
- }
resize需要分情况讨论,如果接收的参数小于当前容量时,空间不进行变动;如果小于当前有效元素个数时,需要更新_finish迭代器达到删除的效果。同时需要注意resize有第二个参数(官方手册)。
- void resize(const size_t n, T val = T())
- {
- if (n > capacity) reserve(n); //大于当前容量,扩容
- if (n > size())
- {
- while (_finish < _start + n)
- {
- *_finish = val;
- ++_finish;
- }
- }
- else _finish = _start + n;
- }
- void push_back(const T& val)
- {
- if (_finish == _endofstorage) //是否需要扩容
- {
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- }
- *_finish = val;
- ++_finish;
- }
- void pop_back()
- {
- assert(!empty()); //尾删容器不能为空
- --_finish;
- }
这里模拟实现:默认构造函数、范围拷贝、指定容器大小、拷贝构造函数(现代写法)、析构函数。
- vector() //默认构造函数
- :_start(nullptr)
- ,_finish(nullptr)
- ,_endofstorage(nullptr)
- {}
-
- template <class it>
- vector(it first, it last) //范围拷贝构造
- : _start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- while (first != last)
- {
- push_back(*first);
- ++first;
- }
- }
-
- //拷贝构造现代写法
- void swap(vector
& v) - {
- std::swap(_start, v._start);
- std::swap(_finish, v._finish);
- std::swap(_endofstorage, v._endofstorage);
-
- }
- vector(const vector
& v) - :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- vector
tmp(v.begin(), v.end()) ; - swap(tmp);
- }
-
- vector(size_t n, const T& val = T()) //指定容器大小构造
- :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- reserve(n);
- for (size_t i = 0; i < n; ++i)
- {
- push_back(val);
- }
-
- }
-
- ~vector() //析构函数
- {
- delete[] _start;
- _start = _finish = _endofstorage = nullptr;
- }
上面的代码会出一个错误:

其原因在于:10 在编译器的视角中默认是一个 int 类型的数,而我们的接口设计是一个 size_t 类型的数,所以会存在一些类型提升。而我们又设计了一个模板,在编译器的视角看来,调用模板函数是开销更小的选择。

解决方案是添加一个重载:
- vector(int n, const T& val = T()) //指定容器大小构造
- :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- reserve(n);
- for (int i = 0; i < n; ++i)
- {
- push_back(val);
- }
- }
需不需要使用 const 函数是看我们需求来的,这里给出设计原则:
上面的代码可能考虑的不够周全,读者可自行改进。下标运算符对于我们来说是可读可写的。
- T& operator[](const size_t n)
- {
- assert(n >= 0 && n < size()); //防止越界
- return _start[n];
- }
-
- const T& operator[](const size_t n) const
- {
- assert(n >= 0 && n < size()); //防止越界
- return _start[n];
- }
-
- vector
& operator=(vector v) //赋值运算符重载 - {
- swap(v);
- return *this;
- }
- void insert(iterator pos,const T& val)
- {
- assert(pos >= _start && pos < _finish);
- if (_finish == _endofstorage) //检查是否需要扩容
- {
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- }
- auto end = _finish - 1;
- while (end >= pos)
- {
- *(end + 1) = *end;
- --end;
- }
- *pos = val;
- ++_finish;
- }
这样设计的接口发生扩容时会产生迭代器失效,因为扩容是异地扩容,就会导致pos指向的空间已经被释放了,需要更新pos。因为是传值调用,我们还必须保证外部的迭代器能够及时更新。
- iterator insert(iterator pos,const T& val)
- {
- assert(pos >= _start && pos < _finish);
- if (_finish == _endofstorage) //检查是否需要扩容
- {
- size_t oldsize = _finish - _start;
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- pos = _start + oldsize; //扩容后,_start的指向已经更改,需要更新pos
- }
- auto end = _finish - 1;
- while (end >= pos)
- {
- *(end + 1) = *end;
- --end;
- }
- *pos = val;
- ++_finish;
- return pos; //添加一个返回值供外部迭代器更新
- }
外部需要继续使用迭代器的正确方法为:

在VS环境中使用标准库的insert接口,不按上面的方式使用迭代器,就会发生迭代器失效问题。

- void erase(iterator pos)
- {
- assert(pos >= _start);
- assert(pos < _finish);
-
- auto del = pos + 1;
- while (del < _finish)
- {
- *(del - 1) = *del;
- ++del;
- }
- --_finish;
- }
这样做会导致迭代器失效。其原因在于:删除最后一个元素,del的位置会指向一个不合法的位置,如果后续要对这个指针指向的内容进行读、写是非常危险的。所以与insert一样,VS的编译环境是使用insert和erase后迭代器失效。解决方案是返回指向删除元素位置的迭代器。
- iterator erase(iterator pos)
- {
- assert(pos >= _start);
- assert(pos < _finish);
-
- auto del = pos + 1;
- while (del < _finish)
- {
- *(del - 1) = *del;
- ++del;
- }
- --_finish;
- return pos;
- }
外部调用时正确的使用方法:

使用标准库中的vector容器,不按上述方法使用会发生错误:
留意刚才的reserve接口:
- void reserve(const size_t& n)
- {
- if (n > capacity())
- {
- T* tmp = new T[n];
- assert(tmp); //检查是否成功开辟
- int oldsize = _finish - _start;
-
- if (_start) //如果_start不为空需要拷贝数据
- {
- memcpy(tmp, _start, sizeof(T) * oldsize);
- delete[] _start; //释放旧空间
- }
-
- //异地扩容,更新迭代器
- _start = tmp;
- _finish = _start + oldsize;
- _endofstorage = _start + n;
- }
- }
这么做会导致一个非常严重的野指针问题:

其原因在于:异地扩容之后,使用memcpy进行拷贝,而这个拷贝是一次浅拷贝,新空间和旧空间的对象都指向原来的_start指向的空间,当_start指向的空间释放后,新空间的对象_start就是野指针了,所以打印的就是乱码。当函数栈帧退出时又析构一次,就会造成一次严重的野指针问题。

所以我们的解决方案是不使用memcpy进行浅拷贝,而是使用赋值运算符重载进行深拷贝。
- void reserve(const size_t n)
- {
- if (n > capacity())
- {
- int oldsize = _finish - _start;
- T* tmp = new T[n];
- assert(tmp); //检查是否成功开辟
-
- if (_start) //如果_start不为空需要拷贝数据
- {
- //memcpy(tmp, _start, sizeof(T) * oldsize);
- for (size_t i = 0; i < size(); i++)
- {
- tmp[i] = _start[i]; //使用赋值运算符重载
- }
- delete[] _start; //释放旧空间
- }
-
- //异地扩容,更新迭代器
- _start = tmp;
- _finish = _start + oldsize;
- _endofstorage = _start + n;
- }
- }
- #include
- #include
- #include
-
- namespace ly
- {
- 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;
- }
-
- vector() //默认构造函数
- :_start(nullptr)
- ,_finish(nullptr)
- ,_endofstorage(nullptr)
- {}
-
- ~vector() //析构函数
- {
- delete[] _start;
- _start = _finish = _endofstorage = nullptr;
- }
-
-
- template <class it>
- vector(it first, it last) //范围拷贝构造
- : _start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- while (first != last)
- {
- push_back(*first);
- ++first;
- }
- }
-
- //拷贝构造现代写法
- void swap(vector
& v) - {
- std::swap(_start, v._start);
- std::swap(_finish, v._finish);
- std::swap(_endofstorage, v._endofstorage);
-
- }
- vector(const vector
& v) - :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- vector
tmp(v.begin(), v.end()) ; - swap(tmp);
- }
-
- vector(size_t n, const T& val = T()) //指定容器大小构造
- :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- reserve(n);
- for (size_t i = 0; i < n; ++i)
- {
- push_back(val);
- }
-
- }
- vector(int n, const T& val = T()) //指定容器大小构造
- :_start(nullptr)
- , _finish(nullptr)
- , _endofstorage(nullptr)
- {
- reserve(n);
- for (int i = 0; i < n; ++i)
- {
- push_back(val);
- }
-
- }
-
- T& operator[](const size_t n)
- {
- assert(n < size()); //防止越界
- return _start[n];
- }
- const T& operator[](const size_t n) const
- {
- assert( n < size()); //防止越界
- return _start[n];
- }
- vector
& operator=(vector v) - {
- swap(v);
- return *this;
- }
-
- void reserve(const size_t n)
- {
- if (n > capacity())
- {
- int oldsize = _finish - _start;
- T* tmp = new T[n];
- assert(tmp); //检查是否成功开辟
-
- if (_start) //如果_start不为空需要拷贝数据
- {
- //memcpy(tmp, _start, sizeof(T) * oldsize);
- for (size_t i = 0; i < size(); i++)
- {
- tmp[i] = _start[i]; //使用运算符重载
- }
- delete[] _start; //释放旧空间
- }
-
- //异地扩容,更新迭代器
- _start = tmp;
- _finish = _start + oldsize;
- _endofstorage = _start + n;
- }
- }
-
-
- void resize(const size_t n, T val = T())
- {
- if (n > capacity) reserve(n); //大于当前容量,扩容
- if (n > size())
- {
- while (_finish < _start + n)
- {
- *_finish = val;
- ++_finish;
- }
- }
- else _finish = _start + n;
- }
-
- size_t size()
- {
- return _finish - _start;
- }
- size_t capacity()
- {
- return _endofstorage - _start;
- }
- void clear()
- {
- _finish = _start;
- }
- bool empty()
- {
- return _finish == _start;
- }
-
- void push_back(const T& val)
- {
- if (_finish == _endofstorage) //是否需要扩容
- {
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- }
- *_finish = val;
- ++_finish;
- }
- void pop_back()
- {
- assert(!empty()); //尾删容器不能为空
- --_finish;
- }
-
- iterator insert(iterator pos,const T& val)
- {
- assert(pos >= _start && pos < _finish);
- if (_finish == _endofstorage) //检查是否需要扩容
- {
- size_t oldsize = _finish - _start;
- size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;
- reserve(newcapacity);
- pos = _start + oldsize; //扩容后,_start的指向已经更改,需要更新pos
- }
- auto end = _finish - 1;
- while (end >= pos)
- {
- *(end + 1) = *end;
- --end;
- }
- *pos = val;
- ++_finish;
- return pos; //添加一个返回值供外部迭代器更新
- }
-
- iterator erase(iterator pos)
- {
- assert(pos >= _start);
- assert(pos < _finish);
-
- auto del = pos + 1;
- while (del < _finish)
- {
- *(del - 1) = *del;
- ++del;
- }
- --_finish;
- return pos;
- }
- private:
- iterator _start;
- iterator _finish;
- iterator _endofstorage;
-
- };
- }