C++ 【vector模拟实现】

目录

1.vector注意事项

2.vector基本模拟实现

insert迭代器失效

erase迭代器失效场景

erase正确写法

总结:insert/erase不要直接访问pos,必须先更新pos位置再访问,不然就会出现迭代器失效

3.拷贝构造:深拷贝

3.2 内置类型升级

3.3 非法的间接寻址

4.赋值运算符


1.vector注意事项

vector构造函数

default(1):不仅仅允许在模板参数中自己定义空间配置器allocator,还允许在构造函数时自定义传递

fill(2):n个val初始vector,size_type(==size_t)和value_type(第一个模板模板参数)是vector tpyedef的成员类型

range(3):迭代器区间构造

copy(4):拷贝构造

C++ 【vector模拟实现】_第1张图片

C++ 【vector模拟实现】_第2张图片


遍历:[]

[]不同于at,at越界抛异常,[]越界assert

返回pos位置数据的引用

C++ 【vector模拟实现】_第3张图片

vector迭代器类模板不能用类名 ,得用模板类型

void testvector1()
	{
		vector v1;
		vector v2(10, 1);
		vector v3(v2);

		for (size_t i = 0; i < v2.size(); ++i)
		{
			cout << ++v2[i] << " ";//[]返回的数据是对应数据的引用
		}
		cout << endl;


		vector::iterator it = v2.begin();
		while (it != v2.end())
		{
			cout << --(*it) << " ";//迭代器可以修改和遍历,但是注意优先级
			++it;
		}
		cout << endl;


		for (auto ch : v2)
		{
			cout<<--ch<<" ";
		}
	}


push_back && pop_back

vector只提供了尾插尾删

const value_type& val == const T& val(T可以是任意类型)

C++ 【vector模拟实现】_第4张图片

C++ 【vector模拟实现】_第5张图片

void testvector4()
	{
		vector s;
		s.push_back("zhangsan");//隐式类型转换
		string str1("lisi");
		s.push_back(str1);
		s.push_back(string("wangwu"));//匿名结构+隐式类型转换
		
		for (auto& e : s)//避免深拷贝
		{
			cout << e << " ";
		}
	}


insert

 vector给的不再是下标位置,而是迭代器

C++ 【vector模拟实现】_第6张图片

 erase

C++ 【vector模拟实现】_第7张图片

void testvector2()
	{
		vector v1(10,2);
		vector::iterator pos = find(v1.begin(), v1.end(),2);
		if (pos != v1.end())//没找到返回end
		{
			v1.insert(pos, 3);
		}

		for (auto ch : v1)
		{
			cout << ch << " ";
		}

		cout << endl;

		pos = find(v1.begin(), v1.end(), 3);
		if (pos != v1.end())//没找到返回end
		{
			v1.erase(pos);
		}

		for (auto ch : v1)
		{
			cout << ch << " ";
		}
	}


sort快排(包含在algorithm头文件中)

传迭代器区间即可排序,默认升序

C++ 【vector模拟实现】_第8张图片

逆序包头文件,其中greater是仿函数(大堆降序)

void testvector3()
	{
		vector v1;
		v1.push_back(53);
		v1.push_back(41);
		v1.push_back(32);
		v1.push_back(512);
		greater gt;
        less ls;//小堆升序
		sort(v1.begin(), v1.end(), gt);
        //sort(v1.begin(), v1.end(),greater());//匿名对象
		for (auto e : v1)
		{
			cout << e << " ";
			e++;
		}


注意:vector没有重载流提取和流插入

resize和reserve

resize改变size和capacity,reserve只改变capacity

2.vector基本模拟实现

vector重要的成员变量是三个迭代器,迭代器是原生指针

C++ 【vector模拟实现】_第9张图片

 begin是第一个位置,finish是最后一个数据的下一个位置,end_of_storage是最后一个位置

#include 
#include 
#include 
#include 
#include 
using namespace std;

namespace My_Vector
{
	template
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		iterator begin()
		{
			return _start;
		}

		iterator end()
		{
			return _finish;
		}

		const_iterator begin() const
		{
			return _start;
		}

		const_iterator end() const
		{
			return _finish;
		}

		vector()
			:_start(nullptr)
			,_finish(nullptr)
			,_end_of_storage(nullptr)
		{}

		~vector()
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}

		size_t capacity() const
		{
			return _end_of_storage - _start;
		}

		size_t size() const
		{
			return _finish - _start;
		} 

		T& operator[](size_t pos)
		{  
			assert(pos < size());
			return _start[pos];
		}

		const T& operator[](size_t pos) const
		{
			assert(pos < size());
			return _start[pos];
		}

		void reserve(size_t n)
		{
			if (n > capacity())
			{
				size_t sz = size();
				T* tmp = new T[n];
				if (_start)
				{
					//memcpy(tmp, _start, sizeof(T) * sz);//memcpy是浅拷贝
                    for(size_t i = 0;i < sz;++i)//完成vector的数据深拷贝,防止析构两次
                    {
                        tmp[i] = _start[i];//调用对应T类型的赋值运算符完成深拷贝
                    }
					delete[] _start;
				}
 				_start = tmp;
				_finish = _start + sz;//如果写成+size(),_strat已经改变结果会出错 
				_end_of_storage = _start + n;
			}
		}
    void resize(size_t n,const T& val = T())
		{
			if (n > capacity())
			{
				reserve(n);
			}
			if (n > size())
			{
				while (_finish < _start + n)//初始化填入数据
				{
					*_finish = val;
					++_finish;
				}
			 }
			else
			{
				_finish = _start + n;
			}
		}

		void push_back(const T& v)
		{
			if (_finish == _end_of_storage)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2); 
			}
			*_finish = v;
			_finish++;
		}

		void pop_back()
		{
			assert(_start < _finish);
			--_finish;
		}
		 
	private:
		iterator _start;
		iterator _finish;
		iterator _end_of_storage;
	};
	}
}

insert迭代器失效

vector没有find

string的find需求不一样(找一个字符或者子串)

vector,list...的find需求是一样的,于是写成了算法,在algorithm头文件中,只需传迭代器即可,注意左闭右开

找不到返回last,第二个模板参数

C++ 【vector模拟实现】_第10张图片

 

错误的insert模拟实现

void insert(iterator pos,const T& x)
		{
			assert(pos >= _start && pos <= _finish);//=finish 为尾插
			if (_finish == _end_of_storage)
			{
				//size_t sz = pos - _start;//解决pos失效问题,不写扩容pos失效出问题
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				//pos = _start + sz;//解决pos失效问题,更新pos位置
			}
			iterator tail = _finish - 1;
			while (tail >= pos)
			{
				*(tail + 1) = *tail;
				--tail;
			}
			*pos = x;
			_finish++;
		}

当insert后出现扩容的情况,便会发生迭代器失效

原因:扩容后_start改变(New开辟新空间),旧空间释放,pos迭代器野指针,解应用野指针报错

解决方法:更新insert内部pos位置

第二个问题:pos指向的位置已经不是原来的值,数据发生挪动。insert内部pos修改并不会影响外面实参pos的位置,insert扩容时下次继续对pos位置insert报错

错误程序:在所有的偶数前面插入一个偶数的二倍

void test_vector4()
	{
		vector v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		
		auto it = v1.begin();
		while (it != v1.end())//在所有的偶数前面插入一个偶数二倍
		{
			if (*it % 2 == 0)
			{
				v1.insert(it, *it * 2);
			}
			++it;
		}

		for (auto e : v1)
		{
			cout << e << " ";
		}
	}

程序崩溃,原因在于插入后pos指向新增insert插入的位置,++it == 2,死循环扩容后pos访问野指针

错误解决方法:void insert(iterator& pos,const T& x)

以下情况无法使用iterator&:

头插时v1.insert(v1.begin(),1);原因在于begin函数是传值返回,生成临时变量,具有常性(引用和指针存在权限问题)

解决方法:接收返回值新插入元素的迭代器位置,更新it

		iterator insert(iterator pos,const T& x)
		{
			assert(pos >= _start && pos <= _finish);//=finish 为尾插
			if (_finish == _end_of_storage)
			{
				size_t sz = pos - _start;
				reserve(capacity() == 0 ? 4 : capacity() * 2);
				pos = _start + sz;//解决pos失效问题
			}
			iterator tail = _finish - 1;
			while (tail >= pos)
			{
				*(tail + 1) = *tail;
				--tail;
			}
			*pos = x;
			_finish++;
			return pos; 
		}
void test_vector4()
	{
		vector v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		
		auto it = v1.begin();
		while (it != v1.end())//在所有的偶数前面插入一个偶数二倍
		{
			if (*it % 2 == 0)
			{
				it = v1.insert(it, *it * 2);
				++it;//++第一次跳过新插入的值
				++it;//++第二次跳过判断的值
			}
			else
			{
				++it;
			}
		}

		for (auto e : v1)
		{
			cout << e << " ";
		}
	}

erase迭代器失效场景

		void erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);//开区间
			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}
			--_finish;

		}

要求删除所有偶数:程序崩溃

void test_vector3()
	{
		vector v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		vector::iterator it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				v1.erase(it);
			}
			++it; 
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
	}

C++ 【vector模拟实现】_第11张图片

要求删除所有偶数:程序正常运行,结果正确

	void test_vector4()
	{
		vector v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		vector::iterator it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				v1.erase(it);
			}
			++it; 
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
	}

运气好

要求删除所有偶数:程序正常运行,结果错误

void test_vector5()
	{
		vector v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(4);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		vector::iterator it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				v1.erase(it);
			}
			++it; 
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
	}

C++ 【vector模拟实现】_第12张图片

erase正确写法

要求删除所有偶数,解决方法:带返回值,返回删除元素的下一个位置迭代器

同时,erase接收返回值,更新下标

iterator erase(iterator pos)
		{
			assert(pos >= _start && pos < _finish);//开区间
			iterator begin = pos + 1;
			while (begin < _finish)
			{
				*(begin - 1) = *begin;
				++begin;
			}
			--_finish;
			return pos;
		}

void test_vector3()
	{
		vector v1;
		v1.push_back(1);
		v1.push_back(2);
		v1.push_back(4);
		v1.push_back(3);
		v1.push_back(4);
		v1.push_back(5);
		vector::iterator it = v1.begin();
		while (it != v1.end())
		{
			if (*it % 2 == 0)
			{
				it = v1.erase(it);
			}
			else
			{
				++it;
			}
		}
		for (auto e : v1)
		{
			cout << e << " ";
		}
	}

总结:insert/erase不要直接访问pos,必须先更新pos位置再访问,不然就会出现迭代器失效


3.拷贝构造:深拷贝

 三个类型都是内置类型(指针),只能完成值拷贝

C++ 【vector模拟实现】_第13张图片

 两种深拷贝写法

注意:不能使用memcpy,vector中T如果是内置类型值拷贝还好,如果还是一个vector或者string,memcpy相当于浅拷贝析构出问题,完成vector内部T数据深拷贝

	vector(const vector& v)
		{
			_start = new T[v.size()];
			//memcpy(_start, v._start, sizeof(T) * v.size());
			for (size_t i = 0; i < v.size(); ++i)
			{
				_start[i] = v._start[i];//内部调用赋值完成深拷贝
			}
			_finish = _start + v.size();
			_end_of_storage = _start + v.size();
		}

		vector(const vector& v)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(v.size());
			for (const auto& e : v)
			{
				push_back(e);
			}
		}

现代写法需要带参构造函数,我们需要再实现一个迭代器区间构造函数

类模板的成员函数还能增添模板,成员函数中可以使用双重模板

再次定义的模板需要迭代器区间,无法使用iterator的原因是不知道模板类型,对象可能不是vector,写成模板可以用其他容器迭代器区间构造,只要迭代器解应用数据类型匹配即可

template          
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			while(first != last)
			{   
				push_back(*first);
				++first;
			}
		}

		void swap(vector& v)
		{
			std::swap(_start,v._start);
			std::swap(_finish,v._finish);
			std::swap(_end_of_storage,v._end_of_storage);
		}

		vector(const vector& v)//v2 = v1
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			vector tmp(v.begin(), v.end());//调用模板构造函数
			swap(tmp);
		}

3.2 内置类型升级

模板的出现让内置类型也有默认构造函数

        int i = 0;
		int j = int();//0
		int w = int(10);

3.3 非法的间接寻址

两个构造函数

vector(size_t n, const T& val = T())
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			reserve(n);
			for (size_t i = 0 ; i < n ; ++i)
			{
				push_back(val);
			}
		}


template          
		vector(InputIterator first, InputIterator last)
			:_start(nullptr)
			, _finish(nullptr)
			, _end_of_storage(nullptr)
		{
			while(first != last)
			{   
				push_back(*first);
				++first;
			}
		}

传两个参数报错:非法的间接寻址

原因在于实例化时编译器寻找最匹配的构造函数,10,1都是int,和半缺省的size_t和T不是最匹配,而和InputIterator模板最匹配,但并不是迭代器区间,不能解应用报错

解决方法,新增一个int重载即可

	void test_vector7()
	{
		//vector v(10, 1);//报错,
		vector v1(10);
		vector v2(10, 'a');
	}

4.赋值运算符

赋值是存在对象,拷贝构造是不存在对象

 传参是构造,直接swap现代写法

vector& operator=(vector v)//v2 = v1;
		{
			swap(v);
			return *this;
		}

你可能感兴趣的:(C++,c++)