C++初阶-vector的模拟实现1
目录
1.序言
2.vector基本结构
3.size()和capacity()的模拟实现
4.begin()和end()函数的模拟实现
5.reserve函数的模拟实现1
6.push_back函数的模拟实现(含empty实现)
6.1解决问题
6.2最终代码(reverse的模拟实现2)
7.operator[]函数的模拟实现
8.pop_back函数的模拟实现
9.insert函数的模拟实现
10.erase函数的模拟实现
11.总结
1.序言
vector的模拟实现不会完全按照vector底层实现vector中的函数,但是会尽量接近,而在这个阶段我也会补充一下平常用得比较多的内容,而且前面的几个模拟实现不一定会是最终版本,所以可能实现的最终版本确定大部分是在vector模拟实现3或者2里面,这个阶段我还会进行举例来进行测试,通过测试得到代码的不足。也希望各位能把每个博客都看完,因为前面肯定是有些函数没有实现,没法测出代码的问题或者不足!
2.vector基本结构
在vector底层结构中我们知道了它的底层结构,所以这里就直接写了:
#include<iostream>
#include<vector>
#include<string>
using namespace std;
//防止命名冲突,用一个命名空间域进行分隔
namespace td
{template<class T>class vector{public:typedef T* iterator;//无参的构造函数的实现vector():_start(nullptr),_finish(nullptr),_end_of_storage(nullptr){ }//析构函数的实现~vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}private:iterator _start;iterator _finish;iterator _end_of_storage;};//为了减少展开命名空间的麻烦,我们直接在命名空间内定义一个测试函数void test(){ }
}
int main()
{//用来测试td::test();return 0;
}
其中_start就是我们之前用来存储数据的数组,由于它是指针,所以可以用来表示首元素的地址。这就是一些简单的函数实现与以后我们测试的函数。
3.size()和capacity()的模拟实现
这个函数在之前的底层结构中返回值是size_type类型,实际上就是size_t类型,所以我们就不要这么麻烦了,也不要像之前的那种实现方式(通过begin()和end()函数以及一些额外的处理得到结果)了,直接返回_finish-_start和_end_of_storage-_start因为我们的我们vector是线性的,不用处理很多情况:
//size()函数的实现
size_t size() const
{return _finish - _start;
}
//capacity()函数的实现
size_t capacity() const
{return _end_of_storage - _start;
}
这个函数就不进行测试了,比较简单。
4.begin()和end()函数的模拟实现
这两个函数很简单,直接返回_start和_finish即可:
//普通的begin()函数的实现
iterator begin()
{return _start;
}
//普通的end()函数的实现
iterator end()
{return _finish;
}
typedef const T* const_iterator;
//const版本的begin的实现
const_iterator begin() const
{return _start;
}
//const版本的end的实现
const_iterator end() const
{return _finish;
}
5.reserve函数的模拟实现1
注:这个函数不是最终版本。
我们通过之前的string的reserve函数的实现知道了,我们应该先创建一个对象,然后再把数据拷贝过去,最后释放旧空间,然后把原变量赋值为新的即可:
//reserve函数的实现1
void reserve(size_t n)
{if (n > capacity()){//开辟新空间T* tmp = new T[n];//拷贝数据memcpy(tmp, _start, sizeof(T) * size());//释放空间delete[] _start;_start = tmp;_finish = _start + size();_end_of_storage = _start + n;}
}
6.push_back函数的模拟实现(含empty实现)
这个函数实现比较简单,首先判断空间是否满,我们可以先实现empty(判空),我们通过手动判断,如果满了则需要扩容,扩容后再进行插入,这里实现还是比较简单的!
//empty函数的实现
bool empty() const
{return begin() == end();
}
//push_back的实现
void push_back(const T& x)
{if (_finish == _end_of_storage){//先扩容//如果没有空间,就初始化为4//否则二倍扩容reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;
}
用以下函数测试一下:
void test()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);
}
则结果为:
为什么会有问题,我们调试一下。
6.1解决问题
我们调试一下:
为什么走完了finish还是0呢,我们可以大胆猜测:size()函数可能有问题!
我们通过size()函数的定义有:
//size()函数的实现
size_t size() const
{return _finish - _start;
}
如果代入表达式,那么最终得到结果:_finish=_finish这就是为什么没有解决的原因,难道把这个size()函数改一下?
不是这样的,我们可以通过发现:如果改变只能改变成其他形式如:end()-begin()那么好像最终还是一样的结果,所以不行。
这里的主要原因是开始_finish指向nullptr,_start指向了tmp,而导致了_finish为空,所以是:_start更新了,而_finish没有更新,故要_finish先更新才行。
所以可以改变一下:
6.2最终代码(reverse的模拟实现2)
注:这个不是最终版本的reverse的实现
//reserve函数的实现2
void reserve(size_t n)
{if (n > capacity()){//开辟新空间T* tmp = new T[n];//拷贝数据memcpy(tmp, _start, sizeof(T) * size());//释放空间delete[] _start;_finish = tmp + size();_start = tmp;_end_of_storage = _start + n;}
}
7.operator[]函数的模拟实现
这个函数实现比较简单,只要返回i位置的值即可:
//普通operator[]的实现
T& operator[](size_t i)
{//需包含头文件:assert.hassert(i < size());return _start[i];
}
//const的operator[]的实现
const T& operator[](size_t i) const
{assert(i < size());return _start[i];
}
8.pop_back函数的模拟实现
这个函数很简单,只要先判断是否为空后再--即可。代码如下:
//pop_back函数的实现
void pop_back()
{assert(_finish > _start);--_finish;
}
9.insert函数的模拟实现
注:这个不是最终版本
首先我们就需要判断空间是否满了,满了则需要扩容,然后每一个数据移动至后一位,然后最后插入该数据,最后再++_finish即可(这里涉及到一个很大的问题,我现在讲解不了,测试这个函数是在一定有问题的!):
//insert函数的实现
void insert(iterator pos, const T& x)
{//判断是否合法assert(pos >= _start);assert(pos <= _finish);//判满if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator it = _finish - 1;//移动数据while (it >= pos){*(it + 1) = *it;--it;}*pos = x;++_finish;
}
10.erase函数的模拟实现
这个函数比较简单,只要先判断该位置是否合法,然后再把该位置后面的数据往前移动一个位置即可。那么代码如下:
//erase函数的模拟实现
void erase(iterator pos)
{assert(pos >= _start);assert(pos <= _finish);if (pos == _finish){pop_back();return;}iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;++it;}--_finish;
}
11.总结
该讲实现了一些比较简单的函数,不过有个函数是非常重要的:insert函数,那个函数测试时是有问题的,这涉及到了迭代器失效的问题,所以我不能很清楚的讲解这个原因,所以下讲将进行讲解:insert的最终实现与迭代器失效。这个迭代器失效我们会在很多地方遇到,所以特意分为一个章节来讲解的。好了,这讲就到这里,喜欢的可以一键三连哦!下讲再见!