C++ vector类的模拟实现
一、定义一个my_vector的命名空间域,以区分和库里面的vector
vector实现图:
#include<iostream>
#include<string.h>
#include<assert.h>
#include<algorithm>
#include<string>
using namespace std;
namespace my_vector
{template<class T>class vector{public:typedef T* iterator;typedef const T* const_iterator;//构造函数vector():_start(nullptr),_finsh(nullptr),_end_of_storage(nullptr){}//构造函数(初始化n个val)vector(int n, const T& val = T()):_start(nullptr), _finsh(nullptr), _end_of_storage(nullptr){resize(n, val);}//构造函数(使用迭代器初始化)//使用迭代器模板template<class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finsh(nullptr), _end_of_storage(nullptr){while (first != last){push_back(*first);++first;}}//拷贝构造(深拷贝)vector(const vector<T>& v):_start(nullptr), _finsh(nullptr), _end_of_storage(nullptr){_start = new T[v.capacity()];//拷贝,不能使用memcpy进行拷贝,memcpy是浅拷贝for (size_t i = 0; i < v.size(); ++i){_start[i] = v._start[i];}_finsh = _start + v.size();_end_of_storage = _start + capacity();}//析构函数~vector(){if (_start != nullptr){delete[] _start;_start = nullptr;_end_of_storage = nullptr;_finsh = nullptr;}}//扩容void reserve(size_t n){//检查扩容if (n > capacity()){size_t oddsize = size();//保存一下原有size,防止一会儿加的时候size发生了变化T* tmp = new T[n];//如果原空间数据不为空,就进行拷贝数据if (_start){//memcpy是浅拷贝,这里如果是对象的赋值,需要使用深拷贝for (size_t i = 0; i < size(); i++){//调用对像的深拷贝tmp[i] = _start[i];}//释放原有空间delete[] _start;}//指向新空间_start = tmp;_finsh = _start + oddsize;_end_of_storage = _start + n;}}//[ ]运算符重载T& operator[](size_t pos){assert(pos < size() );return _start[pos];}//const[ ]运算符重载const T& operator[](size_t pos)const{assert(pos < size());return _start + pos;}//insert(迭代器位置前面插入)void insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finsh);//判断是否扩容if (_finsh == _end_of_storage){//扩容会产生新的空间,会产生迭代器失效的问题,所以我们需要更新迭代器size_t len = pos - _start;size_t new_capacity = capacity() == 0 ? 4 : capacity() * 2;reserve(new_capacity);//更新pospos = len + _start;}//挪动数据iterator end = _finsh - 1;while (end >= pos){*(end + 1) = *end;--end;}//插入数据*pos = x;_finsh++;}//迭代器beginiterator begin(){return _start;}//迭代器enditerator end(){return _finsh;}//const迭代器beginconst_iterator begin()const{return _start;}//迭代器endconst_iterator end()const{return _finsh;}//尾插push_backvoid push_back(const T& x){//判断是否扩容if (_finsh == _end_of_storage){size_t new_capacity = capacity() == 0 ? 4 : capacity() * 2;reserve(new_capacity);}*_finsh = x;++_finsh;}//获取sizesize_t size()const{return _finsh - _start;}//获取capacitysize_t capacity()const{return _end_of_storage - _start;}//erase删除数据iterator erase(iterator pos){assert(pos >= _start && pos < _finsh);iterator it = pos + 1;while (it != _finsh){*(it - 1) = *it;++it;}--_finsh;return pos;//,返回下一个位置,pos就是下一个位置}//尾删void pop_back(){erase(--end());}//resize(开空间和初始化)void resize(size_t n, const T& val = T())//T()就是T类型的匿名对象{if (n < size()){_finsh = _start + n;}else{reserve(n);while (_finsh < _start + n){*_finsh = val;_finsh++;}}}//赋值运算符重载void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finsh, v._finsh);std::swap(_end_of_storage, v._end_of_storage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}private:iterator _start;iterator _finsh;iterator _end_of_storage;};
}
总结:
(1)vector中的erase和insert迭代器对象后,不能在访问这个迭代器,我们认为它失效了,访问的结果未定义
(2)在C++中,有了模板之后,不仅对自定义类初始化会调用默认构造,对自定义类型也会调用,例如:
void test_int()
{int i = 0;//也可以像调用匿名对象一样初始化了int j = int();int k = int(1);
}
二、vector测试函
void test_my_vector1()
{my_vector::vector<int> v1;//push_back测试v1.push_back(8);v1.push_back(88);v1.push_back(888);v1.push_back(8888);for (auto element1 : v1){cout << element1 << "->";}cout << endl;//[ ]运算符重载测试my_vector::vector<int>::iterator it = v1.begin();int i = 0;while (it != v1.end()){v1[i]++;++it;++i;}for (auto element2 : v1){cout << element2 << " ";}cout << endl;//insert测试(迭代器失效)my_vector::vector<int>::iterator it1 = v1.begin() + 1;v1.insert(it1, 8976);for (auto element3 : v1){cout << element3 << " ";}cout << endl;
}
//注意:此处引发的迭代器失效是由于扩容造成的,当扩容的时候,会产生新空间,以前的迭代器就失效了
//insert以后迭代器可能会失效,因为不同平台的失效机制不一样,但是失效的主要原因是扩容,
//所以,在insert之后就不要使用形参迭代器,因为它可能失效了,这是一个高危行为
void test_my_vector2()
{//erase测试my_vector::vector<int> v1;v1.push_back(8);v1.push_back(88);v1.push_back(888);v1.push_back(8888);v1.erase(v1.begin() + 1);for (auto element1 : v1){cout << element1 << "->";}cout << endl;//erase之后,迭代器失效了//vs编译器下会进行强制检查,访问会直接报错
}
//注意:一般情况下,我们默认erase和insert迭代器会失效
//但是,erase会有一个返回值,会返回下一个删除位置的值
void test_my_vector3()
{//使用erase来删除vector中所有的偶数my_vector::vector<int> v1;v1.push_back(2);v1.push_back(4);v1.push_back(7);v1.push_back(1);v1.push_back(3);v1.push_back(24);my_vector::vector<int>::iterator it = v1.begin();while (it != v1.end()){//接收返回值!!!if (*it % 2 == 0){it = v1.erase(it);}else{++it;}}cout << "删除所有偶数后" << endl;for (auto element1 : v1){cout << element1 << "->";}cout << endl;
}
//总结:vector中的erase和insert迭代器对象后,不能在访问这个迭代器,我们认为它失效了,访问的结果未定义
void test_my_vector4()
{my_vector::vector<int> v1;v1.push_back(2);v1.push_back(4);v1.push_back(7);v1.push_back(1);v1.push_back(3);v1.push_back(245);v1.resize(12);for (auto element1 : v1){cout << element1 << " ";}cout << endl;
}
void test_my_vector5()
{//拷贝构造my_vector::vector<int> v1;v1.push_back(2);v1.push_back(4);v1.push_back(7);v1.push_back(1);v1.push_back(3);v1.push_back(25);my_vector::vector<int> v2(v1);for (auto element1 : v2){cout << element1 << " ";}cout << endl;//赋值运算符重载测试=my_vector::vector<int> v3;v3.push_back(8);v3.push_back(88);v3.push_back(888);v3.push_back(8888);my_vector::vector<int> v4;v4 = v3;for (auto element2 : v4){cout << element2 << " ";}cout << endl;
}
void test_my_vector6()
{//初始化测试,初始化4个5my_vector::vector<int> v1(4, 5);for (auto element2 : v1){cout << element2 << " ";}cout << endl;//用迭代器初始化测试string s1("I Love You");my_vector::vector<char> vs(s1.begin(),s1.end());for (auto element2 : vs){cout << element2;}cout << endl;
}
//使用memcpy拷贝问题
//假设模拟实现的vector中的reserve接口中,使用memcpy进行的拷贝,以下代码会发生什么问题?
void test_reserve_memcpy()
{my_vector::vector<string> v1;v1.push_back("1111111111111111111");v1.push_back("2222222222222222222");v1.push_back("3333333333333333333");v1.push_back("444444444444444444");for (auto element : v1){cout << element << " ";}cout << endl;
}
int main()
{test_my_vector1();test_my_vector2();test_my_vector3();test_my_vector4();test_my_vector5();test_my_vector6();test_reserve_memcpy();return 0;
}
结论:(1)上述代码发生的问题是vector是深拷贝,但是bector的空间上存的对象是string数组,使用memcpy导致string对象的浅拷贝
(2)解决方案:
for (size_t i = 0; i < v.size(); ++i)
{_start[i] = v._start[i];
}
T是像string这样的深拷贝的类,调用的是string的复制重载,实现string对对象的深拷贝
(3)如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是
浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。