文章目录
- 一、成员变量
- 二、常用迭代器接口模拟实现
- 三、一些常用接口模拟
- 四、默认成员函数
- 五、功能测试
一、成员变量
我们通过在堆上申请一个数组空间来进行储存数据,我们的成员变量是三个指针变量,分别指向第一个位置、最后储存有效位置的下一个位置以及数组空间的最后位置的下一个位置。
//为了与stl保持一致使用重命名
typedef T* iterator;
typedef const T* const_iterator;iterator _start = nullptr;
iterator _finish = nullptr;
iterator _end_of_storage = nullptr;
二、常用迭代器接口模拟实现
直接返回数组的开始位置和有效数据的下一个位置即可。
//迭代器
//第一个位置
iterator begin()
{return _start;
}//有效数据的下一个位置
iterator end()
{return _finish;
}//重载 const
const iterator begin() const
{return _start;
}const iterator end() const
{return _finish;
}
三、一些常用接口模拟
(1)size
求有效数据的个数,用结束位置下一个位置的指针减去第一个位置的指针就是有效数据的个数了。
size_t size() const
{return _finish - _start;
}
(2)capacity
求容器的容量,用数组空间的最后位置的下一个位置的指针减去第一个位置的指针就是容量的大小了。
size_t capacity() const
{return _end_of_storage - _start;
}
(3)重载[]
//重载 []
T operator[](size_t i)
{//保证i位置符合assert(i < size());return *(_start + i);
}const T operator[](size_t i) const
{//保证i位置符合assert(i < size());return *(_start + i);
}
(4)reserve
预留空间,一般用于扩容,这里需要手动扩容,再拷贝数据,最后再改变成员变量的指向。
void reserve(size_t n)
{//先保存有效数据个数size_t _size = size();//判断是否需要扩容if (n > _size){//手动申请空间iterator tmp = new T[n];//拷贝数据到新空间for (size_t i = 0; i < _size; i++){*(tmp + i) = *(_start + i);}//释放掉原来的空间delete[] _start;//重新改变位置_start = tmp;_finish = _start + _size;_end_of_storage = _start + n;}
}
注意:
a.要先保存 size
,因为在重新指向时需要_start
第一个重新指向新空间,如果此时再去调用size()
函数的话,返回的size
是不确定的。最终导致_finish
指向错误。
b.就是不能使用memcpy
函数进行拷贝,因为memcpy
是浅拷贝,当出现数据是自定义类型而且也是需要申请资源的话就会出现重复释放等问题。如数据储存的是string
类型。
所以需要使用深拷贝。
(5)clear
清空,将_start = _finish
即可。
void clear()
{_finish = _start;
}
(6)insert
在迭代器位置前插入一个元素,并返回新的position
位置。
迭起器失效问题:
插入一个位置可能会扩容,扩容就会导致position
位置失效,所以如果需要扩容就先保存好 position
相对 _start
的位置。
iterator insert(iterator position, const T val)
{//迭代器位置assert(position >= _start);assert(position <= _finish);//空间是否够if (_finish == _end_of_storage){ //保存相对位置size_t _size = position - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);//重新获取position位置position = _start + _size;}//往后移动一位iterator end = _finish;while (end > position){*end = *(end-1);--end;}*position = val;++_finish;return position;
}
(7)push_back
尾插入一个元素,这里直接调用insert即可。
void push_back(T x)
{insert(_finish, x);
}
(8)erase
删除position
位置,返回position
位置的值。
这里也可能会存在迭代器失效问题,如缩容(这里不考虑)、最后一个位置。
//删除迭代器
iterator erase(iterator position)
{//符合位置assert(position >= _start);assert(position < _finish);//覆盖掉positioniterator end = position;while (end < _finish - 1){*end = *(end + 1);++end;}--_finish;//这里返回空,因为position已经失效了if (position == _finish + 1){return nullptr;}return position;
}
(9)empty
是否空。
bool empty() const
{return size() == 0;
}
(10)pop_back
尾删,这里直接调用erase()
即可。
void pop_back()
{if (empty())return;erase(_finish-1);
}
(11)resize
重新定义大小,n小于实际大小就缩小,n大于实际大小就用val来填充。
//重新定义大小void resize(size_t n, T val = T())
{if (n > capacity()){reserve(n);}size_t _size = size();if (n > _size){for (int i = _size; i < n; i++){//直接尾插push_back(val);}}else{_finish = _start + n;}}
(12)swap
交换两个容器。
void swap(vector<T>& x)
{//利用std库中的将指针位置交换即可std::swap(_start, x._start);std::swap(_finish, x._finish);std::swap(_end_of_storage, x._end_of_storage);
}
四、默认成员函数
(1)默认构造
无参构造,给了有默认值,这里不用初始化。
vector() {};
用n个val来初始化
vector(size_t n, T val = T())
{//先预留空间,这样就不用扩容了reserve(n);int i = 0;while (i < n){//尾插push_back(val);++i;}
};
拷贝构造
这里要用深拷贝
vector(vector<T> &x)
{//先预留空间,这样就不用扩容了reserve(x.capacity());//直接将获取的数据插入即可,不用memcpy这种直接拷贝vector<T>::iterator it = x.begin();while (it != x.end()){push_back(*it);++it;}
};
用迭代器区间构造,因为可以用其他的容器来初始化,所以这里再用一个模板。
template <class InputIterator>
vector(InputIterator first, InputIterator last)
{//先预留空间,这样就不用扩容了reserve(last - first);while (first < last){push_back(*first);++first;}
}
因为迭代器区间的构造函数与用n个val来初始化构造会冲突。
为了解决这个问题,使用一个具体一点的n个val来初始化的构造函数
vector(int n, T val = T())
{reserve(n);int i = 0;while (i < n){push_back(val);++i;}
};
(2)析构函数
~vector()
{//释放delete[]_start;_start = _finish = _end_of_storage = nullptr;
}
(3)重载 =
vector<T>& operator=(vector<T> x)
{//利用交换函数,x出了该函数作用域就会销毁,所以不用我们手动销毁原来空间了swap(x);return *this;
}
五、功能测试
(1)内置类型
void test01()
{//n个valxu::vector<int> v1(2,1);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//区间xu::vector<int> v2(v1.begin(), v1.end());for (int i = 0; i < v1.size(); i++){cout << v2[i] << " ";}cout << endl;//赋值xu::vector<int> v3;v3 = v1;for (int i = 0; i < v1.size(); i++){cout << v3[i] << " ";}cout << endl;v1.push_back(2);v1.insert(v1.begin(), 0);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.erase(v1.begin());for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.resize(10, 5);for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;}
(2)自定义类型
void test02()
{//n个valxu::vector<string> v1(2, "aa");for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;//区间xu::vector<string> v2(v1.begin(), v1.end());for (int i = 0; i < v1.size(); i++){cout << v2[i] << " ";}cout << endl;//赋值xu::vector<string> v3;v3 = v1;for (int i = 0; i < v1.size(); i++){cout << v3[i] << " ";}cout << endl;v1.push_back("bb");v1.insert(v1.begin(), "cc");for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.erase(v1.begin());for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;v1.resize(10, "ee");for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;}