栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

初级C++:vector的迷你实现

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

初级C++:vector的迷你实现

文章目录
  • 框架和编译冷知识
  • vector
  • 构造,尾插,reserve、【】遍历、迭代器
  • 拷贝构造、赋值重载的多种写法
  • resize、迭代器区间构造
  • 插入、删除
  • 迭代器失效
  • 结语
  • Bug修正、reserve时memcpy深度的浅拷贝问题

框架和编译冷知识
  • 看别人代码,两成核心,熟悉框架
  • 写一项测试一下,头文件会在源文件里面展开,调用函数时只会向上去全局空间找 不会去命名空间找,不会去类域里面找,个头文件使用了cin,则应该将cin在它上面展开,断点调试。


vector
  • 底层还是顺序表:
  • 构造–>尾插 -->开n个空间reserve -->支持对象【】遍历数据------>支持迭代器遍历----->拷贝构造 -->赋值重载—>resize---->支持用迭代器区间构造---->----->任意位置的插入和删除
  • 写单个函数时,思考要用到哪些成员变量,哪些成员变量要改变,又怎样的改变;和参数之间的成员变量又怎样的交互,是否可以借助第三方完成


构造,尾插,reserve、【】遍历、迭代器

迭代器,对指针的重命名;或对指针的封装

template
	class vector
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;
		vector()
			:_start(nullptr)
			, _finsh(nullptr)
			, _endofstorage(nullptr)
		{}
	private:
		iterator _start;
		iterator _finsh;
		iterator _endofstorage;
	};
-----------------------------------------个数,容量,判空------------------------------------
/计算数组元素个数
size_t size()const
{
	return _finsh - _start;
}
		
/计算数组容量大小
size_t cap()const
		{
			return _endofstorage - _start;
		}
/数组判空
bool empty()
		{
			return size() == 0;
		}
-----------------------------------------push_bcak------------------------------------
void push_back(const T& x)
		{
			if (_finsh == _endofstorage)
			{
				size_t newcap = cap() == 0 ? 5 : cap() * 2;
				reserve(newcap);
			}
			*_finsh = x;
			++_finsh;
			//insert(end(), x);
		}

void reserve(size_t n)
		{
			if (n>cap())
			{
				size_t sz = size(); /记录原finsh相对于start的距离
				T* tmp = new T[n];
				memcpy(tmp, _start,sizeof(T)*sz);
				_start = tmp;
				_finsh = _start + sz;
				_endofstorage = _start + n;
			}
		}

----------------------------------------Operator[]---------------------------------
T& operator[](size_t n)
		{
			assert(n < size());
			return *(_start + n);
		}
const T& operator[](size_t n)const
		{
			assert(n < size);
			return *(_start + n);
		}
iterator begin()		{return _start;}
		const_iterator begin()const { return _start; }
		iterator end()      { return _finsh; }
		const_iterator end()const { return _finsh; }

拷贝构造、赋值重载的多种写法
------------------------------------------------------/v1(v2)--------------------------
		vector(const vector& type)
		{
		/v1开一个和v2一样大空间
			_start = new T[type.cap()];
			/把v2空间的数据拷贝给v1
			memcpy(_start, type._start, sizeof(T) * type.size());
			/更新v1 关于有效数据个数的地址
			_finsh = _start + type.size();
			/更新V1的容量的地址
			_endofstorage = _start + type.cap();
		}
--------------------------------------------------2.0
  /v1(v2)用v2初始化v1
		vector(const vector& v)
			:_start(nullptr)
			, _finsh(nullptr)
			, _endofstorage(nullptr) /先初始化我自己
		{
			reserve(v.cap());   /开一个和v2一样大的空间,有空间就可以搞事情了
			for (const auto& e : v)   /对v2数组每个元素的引用尾插到我这个数组里
			{
				push_back(e);
			}
		}
--------------------------------------------赋值重载 = ---------------------------------
/v1=v2  v2实参传给形参tp,形参是实参的一份临时拷贝,所以tp是v1的深拷贝
		vector& operator=(vector tp)
		{
			swap(tp);
			return *this;
		}
void swap( vector& type)
		{
			std::swap(_start, type._start);
			std::swap(_finsh, type._finsh);
			std::swap(_endofstorage, type._endofstorage);
		}

resize、迭代器区间构造
void resize(size_t n, const T& value = T()) /给缺省初始化
		{
			if (n<=size())
			{
				_finsh = _start + n; /反正后面的你也访问不到
			}
			else
			{
				if (n > cap())
				{
					reserve(n);
				}
				while (_finsh<_start+n)
				{
					*_finsh = value;
					++_finsh;
				}
			}

		}
--------------------------------------------迭代器区间构造 ------------------------------
/类模板的成员函数,可以再定义模板参数
template /模板参数
		vector(Inputiterator first, Inputiterator last)
			:_start(nullptr)
			, _finsh(nullptr)
			, _endofstorage(nullptr)
		{
			while (first!=last)
			{
				push_back(*first);
				++first;
			}
		}
插入、删除
iterator insert(iterator pos, const T& val)
		{
			assert(pos >= begin() && pos <= end());
			
			if (_finsh == _endofstorage)
			{
				size_t len = pos - _start;	/记录pos的相对位置
				size_t newcap = cap() == 0 ? 5 : cap() * 2;
				reserve(newcap);
				pos = begin() + len;
			}
			vector::iterator it = end();
			while (it>=pos)
			{
				*it = *(it - 1);
				--it;
			}
			*pos = val;
			_finsh++;
			return pos;		/返回新位置的迭代器
		}
--------------------------------------------删除---------------------------------
iterator earses(iterator pos)/删除一个,删除多个就是resize了
		{
			/返回指向删除数据的下一个数据位置
			assert(pos >= begin() && pos <= end());
			auto it = pos;
			while (it!=_finsh)
			{
				*it = *(it + 1);
				++it;
			}
			--_finsh;
			return pos;
		}
迭代器失效

find某个值,返回该值的迭代器,然后进行插入,如果遇到增容,则该迭代器原空间可能会被销毁,再用迭代器可能造成野指针访问,
或者原空间没有销毁,但指向空间的值改变了。

结语

好了,这篇水文到此结束,感谢大家的阅读点赞收藏,我们下篇文章再见!有点小迷,但说不出来哪里米,可能处处迷…

Bug修正、reserve时memcpy深度的浅拷贝问题
void reserve(size_t n)
		{
			if (n>cap())
			{
				size_t sz = size(); /记录原finsh相对于start的距离
				T* tmp = new T[n];
				if(_start)
				{
					memcpy(tmp, _start,sizeof(T)*sz); 
					delete{} _start;  
		/假设这里T是string 对象 ,清理时,则会先调用string对象的析构,再释放_start					
				}
				_start = tmp;
				_finsh = _start + sz;
				_endofstorage = _start + n;
			}
		}

int main()
{
	vector v1;
	reserve(2);
	v1.push_back("11111");
	v1.push_back("11111");
	v1.push_back("11111");/扩容 memcpy 后释放 已经清理了string 的_str
	return 0;
	
}/v 走到这里时,会再次调用string 的析构_str ,释放了两次

       -------------修正-------------
       
void reserve(size_t n)
		{
			if (n>cap())
			{
				size_t sz = size(); /记录原finsh相对于start的距离
				T* tmp = new T[n];
				if(_start)
				{
					for(size_t i=0;i
						tmp[i]=_start[i]
						/如果是string 对象,则是调用对象的深拷贝,
						delete[] _start; 
					}				
				}
				_start = tmp;
				_finsh = _start + sz;
				_endofstorage = _start + n;
			}
		}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/975119.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号