目录
1、vactor的模拟实现
1.1 成员变量
1.2 size、capacity
1.3 迭代器
1.4 构造、析构、拷贝构造、operator=
1.5 push_back、pop_back、reserve
1.6 operator[]
1.7 insert、erase
1.8 resize
2、使用memcpy拷贝问题
1、vactor的模拟实现
1.1 成员变量
vector是顺序表,但是并不像之前在数据结构中一样会有一个指针动态开辟出的空间的指针、size、capacity,而是由3个指针构成的
1.2 size、capacity
1.3 迭代器
1.4 构造、析构、拷贝构造、operator=
因为类对象会开辟空间,所以要自己实现深拷贝的拷贝构造和operatpr=
1.5 push_back、pop_back、reserve
此时这个reserve是有问题的
1.6 operator[]
1.7 insert、erase
此时也会有迭代器失效问题,因为如果需要增容,通过reserve增完后,_start、_finish、_endofstorage都指向了新的空间,而pos仍然指向原来的空间,所以需要更新pos的位置
1.8 resize
2、使用memcpy拷贝问题
在上面的reserve中使用了memcpy,在遇到自定义类型时会出错,因为memcpy是浅拷贝
问题分析:
1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
2. 如果拷贝的是内置类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。
结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃
上面的tmp[i]=_start[i]也不一定是string的operator=,应该是T的operator=,只是这里是string的
#include<iostream>
#include<cassert>
using namespace std;
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;}/*Vector(const Vector<T>& v){_start = new T[v.capacity()];_finish = _start;_endofstorage = _start + capacity();for (size_t i = 0; i < v.size(); i++){*_finish = v[i];_finish++;}}*//*Vector(const Vector<T>& v){_start = new T[v.capacity()];_finish = _start + v.size();_endofstorage = _start + v.capacity();memcpy(_start, v._start, sizeof(T) * v.size());}*/Vector(const Vector<T>& v):_start(nullptr), _finish(nullptr), _endofstorage(nullptr){reserva(v.capacity());//防止push_back频繁扩容for (const auto& e : v)push_back(e);}//Vector<T>& operator=(const Vector<T>& v)//{// if (this != &v)// {// delete[] _start;// _start = new T[v.capacity()];// memcpy(_start, v._start, sizeof(T) * v.size());// //也可以一个一个赋值// }// return *this;//}void swap(Vector<T>& v){::swap(_start, v._start);::swap(_finish, v._finish);::swap(_endofstorage, v._endofstorage);//这里是在局部调用全局的swap,所以前面加::}Vector<T>& operator=(Vector<T> v){swap(v);return *this;}//for (size_t i = 0; i < sz; i++)//{// tmp[i] = _start[i];//利用string的operator=的深拷贝//}void reserve(size_t n){if (n > capacity()){size_t sz = size();//先记录_finish相对_start的偏移量T* tmp = new T[n];if (_start){注意这里一定要判断一下,当_start是空的时候使用memcoy会报错且因为_start是空,也没必要将上面的内容拷贝到tmp上memcpy(tmp, _start, sizeof(T) * size());delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}void push_back(const T& x)//用引用是因为T可能是自定义类型{if (_finish == _endofstorage)//满了则扩容{size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);}*_finish = x;++_finish;//insert(_finish, x);也可以直接复用insert}void pop_back(){assert(_start < _finish);//保证不为空_finish--;//erase(_finish-1);//也可复用erase}void insert(iterator pos, const T& x){assert(pos <= _finish);if (_finish == _endofstorage){size_t n = pos - _start;//计算pos相对_start的偏移量size_t newcapacity = capacity() == 0 ? 2 : capacity() * 2;reserve(newcapacity);pos = _start + n;//更新pos的位置}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;end--;}*pos = x;_finish++;}iterator erase(iterator pos){assert(pos < _finish);//确保删除位置有效iterator it = pos;while (it < _finish){*it = *(it + 1);it++;}_finish--;return pos;//删除后原本的下一个就到了pos的位置//所以返回迭代器就是返回原来的位置}void resize(size_t n, const T& val = T()){//上面给的缺省值不能给0,因为不一定是int类型,T()是针对任何类型的//int i = int(); -> i=0;//int i = int(7) -> i=7;//C++为了让内置类型可以兼容模板if (n <= size())//如果比size还小或等于,不用填充,直接缩小{_finish = _start + n;}else//需要填充{if (n > capacity())//扩容{reserve(n);}//填充,从_finish的位置开始向后填充//填充时不能用memcpy将val直接弄到_finish到_start+n的位置//因为memcpy是浅拷贝,若是自定义类型且开辟了空间//会直接让所以的都指向同一块空间while (_finish < _start + n){*_finish = val;_finish++;}}}T& operator[](size_t i)//可读可写{assert(i < size());//断言,防止i越界return _start[i];}const T& operator[](size_t i) const//只可读{assert(i < size());//断言,防止i越界return _start[i];}size_t size() const{return _finish - _start;}size_t capacity() const{return _endofstorage - _start;}
private:iterator _start;//指向动态开辟数组的起始位置iterator _finish;//指向动态开辟数组的有值的下一个位置iterator _endofstorage;//指向动态开辟数组的末尾
};