前面的文章中,给出了对于的模拟实现,本篇文章将给出关于的模拟实现。
目录
1.基本框架:
2. 返回值与迭代器:
2.1 返回值capacity与size:
2.2 两种迭代器iterator和const_iterator:
3. 扩容与push_back与pop_back:
3.1 扩容:
3.2 push_back:
3.3 pop_back:
4. 运算符重载[]:
测试:
5. 拷贝构造函数:
6. 运算符重载=:
7. 打印函数print_vecotr:
测试:
8. 插入insert:
9. resize(n):
10. erase:
测试:
11. 代码总览:
1.基本框架:
对于类,主要是针对于字符型变量这一种数据类型,但是对于,要同时适用于不同的数据类型,对于这一点,可以利用之前C++(10)——模板-CSDN博客中的模板参数来实现。在中的源代码中,类中的成员变量分别为。三个变量的类型都是迭代器。其中表示开头,表示已有内容的结尾,表示开辟空间的结尾。
通过上述信息,可以给出类的基本构成:
namespace violent
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;private:iterator _start;iterator _finish;iterator _endofstorage;};
}
对于的构造函数,直接初始化为即可。因为三个成员变量的类型是由内置类型经过后的,因此,三个成员变量的类型可以看作内置类型,对于内置类型的初始化,可以通过声明成员变量的同时,给缺省值来达成。即:
namespace violent
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector(){}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};
}
对于类的析构函数,只需要先检测是否为空,为空则说明外部没有对实例化的对象进行操作。如果不为空,则需要调用析构函数,对于对象进行清理。
~vector(){if (_start){delete[]_start;_start = _finish = _endofstorage = nullptr;}}
2. 返回值与迭代器:
2.1 返回值capacity与size:
在上一部分说到了三个成员变量各自的意义,具体可以由下面的图形表示:
通过对于三个成员变量进行计算,可以得到空间中已有内容的长度,空间的整体大小。代码如下:
size_t capacity() const{return _endofstorage - _start;}size_t size() const{return _finish - _start;}
2.2 两种迭代器iterator和const_iterator:
同时为了方便后续使用迭代器,需要获取空间的起始地址,空间的末尾地址,代码表示如下:
iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}
3. 扩容与push_back与pop_back:
3.1 扩容:
对于扩容,其整体思路如下:
假设已有的空间的首地址为,即:
如果已有的空间不满足使用需求,需要开辟大小为的空间,则通过操作符来开辟一块大小为的空间,这里将这块空间命名为,即:
如果对应的空间中没有内容,即为空,则直接让即可。
如果的空间中存在内容,则先使用函数将内容拷贝到中,再释放掉。最后
在上述步骤结束后,需要修订扩容后空间的。
对于同一块空间,。。
但是,由于会改变,并且当存在内容时会进行释放。因此上述计算方法便不再成立。应在开辟空间之前,提前算出中已有内容的长度,后续进行计算,即:
void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];int oldlen = size();if (_start){ memcpy(tmp, _start, sizeof(T) * oldlen);delete[] _start;}_start = tmp;_finish = _start + oldlen;_endofstorage = _start + n;}}
3.2 push_back:
再进行插入之前,首先需要检查空间是否已满,即,如果相等,则需要进行扩容,再进行插入。具体代码如下:
void push_back(const T& x){if (_finish == _endofstorage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;}
3.3 pop_back:
原理较为简单,不进行过多叙述,只给出代码:
void pop_back(){if (size() > 0){_finish--;}}
4. 运算符重载[]:
与类型中的实现方法相同,这里不过多解释,只给出代码:
T& operator[](size_t pos){return _start[pos];}const T& operator[](size_t pos) const{return _start[pos];}
测试:
利用下方代码对于上面给出的函数进行测试:
void test1(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it1 = v.begin();for (auto e : v){cout << e << ' ';}cout << endl;for (size_t i = 0; i < v.size(); i++){v[i]++;cout << v[i] << ' ';}v.pop_back();v.pop_back();cout << endl;for (size_t i = 0; i < v.size(); i++){cout << v[i] << ' ';}}
运行结果如下:
5. 拷贝构造函数:
由于类中存在指针,因此拷贝构造函数需要实现深拷贝,即:
vector(const vector<T>& x){_start = new T[x.capacity()];memcpy(_start, x._start, sizeof(T) * x.size());_finish = _start + x.size();_endofstorage = _start + x.capacity();}
通过上述代码不难发现,深拷贝就是需要将传参的对象中的内容,空间等一一赋给。
对于上述功能,通过_函数也可以实现,因此,对于拷贝构造函数可以化简为以下形式:
vector(const vector<T>& x){for (auto e : x){push_back(e);}}
6. 运算符重载=:
对于上方的拷贝构造,是利用一个已有的对象去初始化另一个对象。对于运算符重载,则是已有两个一直的对象,用一个对象去给另一个对象赋值。赋值方法与类中的实现方法相同,这里只给出代码,不做过多解释:
void swap(vector<T> x){std::swap(_start, x._start);std::swap(_finish, x._finish);std::swap(_endofstorage, x._endofstorage);}vector<T>& operator=(vector<T> x){swap(x);return *this;}
7. 打印函数print_vecotr:
void print_vector(const vector<T>& x){cout << endl;vector<T>::const_iterator it2 = x.begin();while (it2 != x.end()){cout << *it2 << ' ';it2++;}cout << endl;for (auto e : x){cout << e << ' ';}}
测试:
利用下方的代码对于上述函数进行测试:
void test2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int> v1 = v;for (auto e : v1){cout << e << ' ';}cout << endl;vector<int> v2;v2 = v;for (auto e1 : v2){cout << e1 << ' ';}v2.print_vector(v2);}
运行结果如下:
8. 插入insert:
对于,即在给出的位置插入给定的字符。
在进行插入前,首先需要检测给出的位置是否合法。即。
在检查结束后,需要查看是否需要扩容。随后,利用函数将位置即以后的字符向后整体移动一位,最后在位置插入字符。
对于上述步骤,需要主语,如果发生了扩容,需要提前记录的位置,记录的方法,需要计算出位置到首地址这部分的内容的长度,即。如果发生了扩容,则在扩容结束后,让。具体代码如下:
void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){int len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}memmove(pos + 1, pos, sizeof(T) * (_finish - pos));*pos = x;++_finish;}
9. resize(n):
对于,即改变容量兼初始化:
当时,需要进行缩容。此处由于不涉及扩容,因此直接改变为即可。
当时,并不需要额外开辟空间,后面的空间进行初始化即可
当时,需要先扩容再初始化。这里为了方便理解以及简化代码,将后两种情况合并。
具体代码如下:
void resize(size_t n, T val = T()){if (n > capacity()){reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}
10. erase:
函数为清除给定位置的内容,即从位置开始,让的内容赋值给。具体代码如下:
void erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);while (pos < _finish){*pos = *(pos + 1);++pos;}--_finish;}
测试:
通过下面给出的代码对上述函数进行测试:
void test2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int> v1 = v;for (auto e : v1){cout << e << ' ';}cout << endl;vector<int> v2;v2 = v;for (auto e1 : v2){cout << e1 << ' ';}v2.print_vector(v2);}void test3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto e : v){cout << e << ' ';}cout << endl;v.insert(v.begin(), 11);v.insert(v.begin(), 21);v.insert(v.begin(), 31);v.insert(v.begin(), 41);for (auto e : v){cout << e << ' ';}cout << endl;v.resize(15);for (auto e : v){cout << e << ' ';}cout << endl;v.erase(v.begin());v.erase(v.begin());for (auto e : v){cout << e << ' ';}}
运行结果如下:
11. 代码总览:
#include<iostream>
#include<assert.h>
using namespace std;namespace violent
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector(){}/*vector(const vector<T>& x){_start = new T[x.capacity()];memcpy(_start, x._start, sizeof(T) * x.size());_finish = _start + x.size();_endofstorage = _start + x.capacity();}*/vector(const vector<T>& x){for (auto e : x){push_back(e);}}void swap(vector<T> x){std::swap(_start, x._start);std::swap(_finish, x._finish);std::swap(_endofstorage, x._endofstorage);}vector<T>& operator=(vector<T> x){swap(x);return *this;}iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}size_t capacity() const{return _endofstorage - _start;}size_t size() const{return _finish - _start;}void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];int oldlen = size();if (_start){ memcpy(tmp, _start, sizeof(T) * oldlen);delete[] _start;}_start = tmp;_finish = _start + oldlen;_endofstorage = _start + n;}}void push_back(const T& x){if (_finish == _endofstorage){size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);}*_finish = x;_finish++;}void pop_back(){if (size() > 0){_finish--;}}T& operator[](size_t pos){return _start[pos];}const T& operator[](size_t pos) const{return _start[pos];}void print_vector(const vector<T>& x){cout << endl;vector<T>::const_iterator it2 = x.begin();while (it2 != x.end()){cout << *it2 << ' ';it2++;}cout << endl;for (auto e : x){cout << e << ' ';}}void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){int len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}memmove(pos + 1, pos, sizeof(T) * (_finish - pos));*pos = x;++_finish;}void resize(size_t n, T val = T()){if (n > capacity()){reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{_finish = _start + n;}}void erase(iterator pos){assert(pos >= _start);assert(pos <= _finish);while (pos < _finish){*pos = *(pos + 1);++pos;}--_finish;}~vector(){if (_start){delete[]_start;_start = _finish = _endofstorage = nullptr;}}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};void test1(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator it1 = v.begin();for (auto e : v){cout << e << ' ';}cout << endl;for (size_t i = 0; i < v.size(); i++){v[i]++;cout << v[i] << ' ';}v.pop_back();v.pop_back();cout << endl;for (size_t i = 0; i < v.size(); i++){cout << v[i] << ' ';}}void test2(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int> v1 = v;for (auto e : v1){cout << e << ' ';}cout << endl;vector<int> v2;v2 = v;for (auto e1 : v2){cout << e1 << ' ';}v2.print_vector(v2);}void test3(){vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);for (auto e : v){cout << e << ' ';}cout << endl;v.insert(v.begin(), 11);v.insert(v.begin(), 21);v.insert(v.begin(), 31);v.insert(v.begin(), 41);for (auto e : v){cout << e << ' ';}cout << endl;v.resize(15);for (auto e : v){cout << e << ' ';}cout << endl;v.erase(v.begin());v.erase(v.begin());for (auto e : v){cout << e << ' ';}}
}
#include"vector.h"int main()
{/*violent::test1();violent::test2();*/violent::test3();return 0;
}