前言
因为学习了vector的相关知识,了解了vector大部分接口的底层实现原理,所以我决定自己模拟实现一个mini版的vector类,用来加深对vector各方面知识的理解。
如果有错误或不足之处,还望各位读者小伙伴们指出。
一、包含的相关头文件
#include<iostream> #include<assert.h> #include<vector>//要使用vector类,要记得包含这个头文件 using namespace std;
二、构造和析构
1.构造函数
1.无参
vector() :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) {}
2.n个T型元素进行初始化
1.普通
vector(size_t n, const T& value = T()) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { reserve(n); //for (size_t i = 0; i < n; ++i) //{ // push_back(value); //} while (n--) { push_back(value); } }
2.特殊
因为,编译器会匹配最优匹配的函数进行调用。
为了避免将用n个Int型元素构造一个vector型的对象的函数调用匹配到下面的用T类型的迭代器初始化vector型的对象的构造函数(会发生错误的间接寻址),我们就得重载一个用n个Int数据初始化vector的构造函数
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); } }
3.T型迭代器
template<class InputIterator> vector(InputIterator first, InputIterator last) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { while (first != last) { push_back(*first); first++; } }
2.拷贝构造
现代写法的优点在模拟实现string中已经介绍过,此处不再赘述。
//拷贝构造(现代写法) vector(const vector<T>& v) :_start(nullptr) , _finish(nullptr) , _endOfStorage(nullptr) { vector<T> temp(v.begin(), v.end()); Swap(temp); }
自己实现的Swap可以避免深拷贝,提高效率
void Swap(vector<T>& v) { std::swap(_start, v._start); std::swap(_finish, v._finish); std::swap(_endOfStorage, v._endOfStorage); }
3.赋值运算符重载
//赋值运算符重载 vector<T>& operator= (vector<T> v) { Swap(v); return *this; }
4.析构函数
//析构 ~vector() { delete[] _start; _start = _finish = _endOfStorage = nullptr; }
三、iterator
Vector的迭代器是一个原生指针
typedef T* iterator; typedef const T* const_iterator;
1.普通对象
返回迭代器
iterator begin() { return _start; } iterator end() { return _finish; }
2.const对象
返回const迭代器
const_iterator begin() const { return _start; } const_iterator end() const { return _finish; }
四、modify
1.push_back
尾插
void push_back(const T& x) { if (_finish == _endOfStorage)//插入前要判断空间是否满了 { size_t newcapacity = (capacity() == 0) ? 4 : 2 * capacity();//要坚持是否第一次扩容 reserve(newcapacity); } *_finish = x; _finish++; }
2.pop_back
尾删
void pop_back() { assert(!empty());//如果空间中没有元素就不能再尾删了 _finish--; }
3.insert(含迭代器失效问题)
某个位置插入元素
这里有一个迭代器失效的问题,要小心处理
iterator insert(iterator pos, const T& x) { assert(pos >= _start); //assert(pos < _finish); assert(pos <= _finish); if (_finish == _endOfStorage)//如果插入操作进行了扩容,则原pos指针会失效(异地扩容会改变地址) { size_t len = pos - _start; size_t newcapacity = (capacity() == 0) ? 4 : 2 * capacity(); reserve(newcapacity); //更新pos pos = _start + len; } iterator end = _finish;//挪动元素 while (end > pos) { *end = *(end - 1); end--; } *pos = x;//插入元素 _finish++; return pos;//pos是传值传参,因此函数内pos的更新不会使函数外的pos被更新(即,函数外的pos仍然失效)因此为了继续在函数外使用pos,我们把更新后的pos作为返回值传回去,更新函数外的pos }
具体如何处理下文的测试函数部分有介绍。
4.erase(含迭代器失效问题)
某位置删除一个元素
此处的迭代器意义发生改变,即迭代器失效
iterator erase(iterator pos) { assert(pos >= _start); assert(pos < _finish); //iterator begin = pos + 1; //while (begin < _finish) //{ // *(begin - 1) = *begin; // begin++; //} iterator begin = pos; while (begin < _finish - 1) { *begin = *(begin + 1); begin++; } --_finish; return pos; }
具体如何处理下文的测试函数部分有介绍。
5.clear
void clear() { _finish = _start; }