C++:vector

2023-09-21 12:25:37

目录

vector的模拟实现

一.初定义

二.相关功能

2.1 迭代器

2.2 capacity

1.size

2.capacity

3.reserve(扩容)

4.resize

2.3 access

2.4 modify

1.push_back

2.pop_back

3.empty

4.swap

5.insert

6.erase

2.5构造函数与析构函数

1.构造函数

2.析构函数

3.拷贝构造

4.运算符重载

5.迭代器区间构造

三.迭代器失效与深浅拷贝

1.迭代器失效

2.深浅拷贝


vector的模拟实现

一.初定义

vector:

	template<class T>
	class Vector 
	{
	public:
		typedef T* iterator;
		typedef const T* const_iterator;

	private:
		iterator _start = nullptr;// 指向数据块的开始
		iterator _finish = nullptr;// 指向有效数据的尾
		iterator _end_of_storage = nullptr;// 指向存储容量的尾
	};

二.相关功能

2.1 迭代器

		//迭代器原生指针
		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;
		}

2.2 capacity

1.size

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

2.capacity

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

3.reserve(扩容)

1.判断是否需要扩容

2.开辟新空间,将原来的数据拷贝过去(存一下原来的size)

3.释放掉旧空间,并更新_start,_finish,_end_of_storage

		void reserve(size_t n) 
		{
			if (n > capacity()) 
			{
				//存一下size
				size_t sz = size();
				//开新空间,扩容
				T* tmp = new T[n];

				if (_start) 
				{
					//拷贝原来的数据(深拷贝)
					for (size_t i = 0; i < sz; i++) 
					{
						tmp[i] = _start[i];
					}
                    delete[] _start;//释放原来的空间    
				}
		
				_start = tmp;//更新
				_finish = tmp + sz;
				_end_of_storage = tmp + n;
			}
		}

4.resize

1.若n < size() : 删除数据(更改_finish)

2.若n > capacity() :扩容(使用reserve复用)

3.将多的空间使用value初始化,并更新_finish

--这里给的缺省值,是使用匿名对象构造生成的

		void resize(size_t n, const T& value = T()) 
		{
			if (n < size()) //小于有效数据删除
			{
				_finish = _start + n;
			}
			else
			{
				if(n > capacity())//扩容
					reserve(n);

				while (_finish != _start + n) 
				{
					*_finish = value;
					++_finish;
				}
			}
		}

2.3 access

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

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

2.4 modify

1.push_back

1.检查是否需要扩容

2.尾插数据

		void push_back(const T& x) 
		{
			//扩容
			if (_finish == _end_of_storage) 
			{
				reserve(capacity() == 0? 4:  2*capacity());
			}
			//尾插数据
			*_finish = x;
			_finish++;
		}

2.pop_back

		void pop_back() 
		{
			assert(!empty());
			_finish--;
		}

3.empty

		bool empty() 
		{
			return _finish == _start;
		}

4.swap

		void swap(Vector<T>& v) 
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage,v._end_of_storage);
		}

5.insert

1.检查pos是否在区间内

2.检查是否需要扩容

        --若扩容,更新pos(避免迭代器失效)记录pos相对于_start的位置,扩容后更新

3.挪动数据

4.在pos位置插入数据

		iterator insert(iterator pos, const T& x) 
		{
			assert(pos >= _start && pos <= _finish);
			//判断是否扩容
			if (_finish == _end_of_storage) 
			{
				size_t len = pos - _start;
				reserve(capacity() == 0 ? 4 : 2 * capacity());
				pos = _start + len;//扩容后更新pos,避免迭代器失效
			}
			//1.挪动数据
			iterator end = _finish;
			while (end > pos) 
			{
				*end  = *(end-1);
				end--;
			}
			//2.在pos位置插入数据
			*pos = x;
			_finish++;
			return pos;
		}

6.erase

1.检查pos位置是否合法

2.挪动数据覆盖

		iterator erase(iterator pos) 
		{
			assert(pos>= _start && pos<_finish);
            //挪动数据
			iterator end = pos;
			while (end < _finish) 
			{
				*(end) = *(end + 1);
				end++;
			}
            //表示删除数据
			_finish--;
			return pos;
		}

2.5构造函数与析构函数

1.构造函数

		// 构造函数与析构函数
		//构造函数
		Vector() {}
		
		Vector(int n, const T& value = T()) 
		{
            //尾插n次value
			reserve(n);
			for (int i = 0; i < n; i++) 
			{
				push_back(value);
			}
		}

效果:

2.析构函数

		//析构函数
		~Vector() 
		{
			delete[] _start;
			_start = _finish = _end_of_storage = nullptr;
		}

3.拷贝构造

1.传统写法:


		Vector(const Vector<T>& v)
		{
            //开新空间
			_start = new T[v.capacity()];
			//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.capacity();
		}

2.现代写法:

		//拷贝构造(现代写法)
		Vector(Vector<T>& v) 
		{
			Vector<T> tmp(v.begin(),v.end());
			swap(tmp);
		}

效果:

4.运算符重载

传统写法

Vector<T>& operator=(const Vector<T>& v) 
{
    if (this == &v) {
        return *this; // 自我赋值,不执行任何操作
    }

    // 释放原始资源
    delete[] _start;

    // 分配新资源
    _start = new T[v.capacity()];
    
    // 复制元素
    for (size_t i = 0; i < v.size(); ++i)
    {
        _start[i] = v._start[i];
    }

    _finish = _start + v.size();
    _end_of_storage = _start + v.capacity();
    return *this;
}

现代写法

		void swap(Vector<T>& v) 
		{
			std::swap(_start, v._start);
			std::swap(_finish, v._finish);
			std::swap(_end_of_storage,v._end_of_storage);
		}	

        //v1 = v2,(现代写法)
		Vector<T>& operator= (Vector<T> v) 
		{
			swap(v);
			return *this;
		}

5.迭代器区间构造

		//迭代器区间构造
		template<class InputIterator>
		Vector(InputIterator first, InputIterator last) 
		{
			while (first != last) 
			{
				push_back(*first);
				++first;
			}
		}

三.迭代器失效与深浅拷贝:

1.迭代器失效

  • 野指针:vector扩容后,释放掉之前的空间,开辟新的空间,原来的iterator此时指向了被释放的空间
  • 指向内容含义改变:vector的插入操作,可能会挪动数据,挪动后,iterator就不再指向原来的数据(含义改变)

解决:

1.更新迭代器

2.insert等函数,返回删除元素的下一个位置

一般执行相关操作后,都默认该迭代器失效

2.深浅拷贝

  • 浅拷贝是指在复制对象时,只复制对象的成员变量的值
  • 深拷贝是指在复制对象时,不仅复制对象的成员变量的值,还复制对象所拥有的资源,例如动态分配的内存

在类中,实例化对象后用一个对象拷贝构造另外一个对象,若是浅拷贝(只复制值)则会导致两个对象都指向同一块空间,最后调用析构函数的时候,会释放同一块空间两次,

所以需要深拷贝

更多推荐

【算法】矩阵快速幂优化动态规划

文章目录知识讲解题目列表[矩阵快速幂]题目列表📕70.爬楼梯解法1——线性DP解法2——矩阵快速幂509.斐波那契数1137.第N个泰波那契数1220.统计元音字母序列的数目解法1——线性DP解法2——矩阵快速幂优化DP552.学生出勤记录II(🚹递归公式&矩阵快速幂优化🐂)解法1——动态规划解法2——矩阵快速幂

avformat_find_stream_info 为什么总是等到超时或超过大小才退出?

avformat_find_stream_info为什么总是等到超时或超过大小才退出?/*author:hjjdebug*date:2023年09月21日星期四11:05:56CST*description:avformat_find_stream_info为什么不能正常退出了?*/查文档:mpegts:scan_al

Java版工程行业管理系统源码-专业的工程管理软件- 工程项目各模块及其功能点清单

鸿鹄工程项目管理系统SpringCloud+SpringBoot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统1.项目背景一、随着公司的快速发展,企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性,公司对内部工程管理的提升提出了更高的要求。二、企业通过

学信息系统项目管理师第4版系列09_配置管理

1.配置管理1.1.应用技术的和管理的指导和监控方法以标识和说明配置项的功能和物理特征,控制这些特征的变更,记录和报告变更处理和实现状态并验证与规定的需求的遵循性1.1.1.GB/T11457《信息技术软件工程术语》2.配置项2.1.ConfigurationItem,CI2.2.为配置管理设计的硬件、软件或二者的集合

停车场系统、智慧城市停车、智慧社区、物业管理、新能源充电、人脸门禁 uniapp 系统源码

1.智慧停车支持模式封闭性单个停车场路边停车(车位级管理)大小场(场中场),多场子并行或嵌套所有者模式统一平台管理总平台下子账号(区域代理)自建场地资源,自行维护数据总平台下子账号(区域代理)再分配和单个停车场管理人员(物业管理/维保/保安/财务等人员)场站管理【车位控制】精准的实时车位统计和数据及时推送到场地led/

智汇云舟入选《2023全国企业数字化应用优秀解决方案》报告

&nbsp;&nbsp;&nbsp;&nbsp;近日,由中国国际数字经济博览会组委会主办,中关村数字经济产业联盟、河北省数字经济联合会、衡水市人民政府共同承办的2023中国国际数字经济博览会首届全国企业数字化应用生态大会在石家庄举行。会上重磅发布了《2023全国企业数字化应用场景与解决方案》研究报告,智汇云舟“视频孪生

Vue中的路由懒加载:提高性能和用户体验

Vue中的路由懒加载:提高性能和用户体验在现代Web应用程序中,性能和用户体验是至关重要的。为了加速页面加载速度和提高用户感知的响应性,Vue提供了一种路由懒加载的方法。本文将详细介绍Vue中如何进行路由懒加载,并提供代码示例来演示如何实现它。什么是路由懒加载?路由懒加载是一种技术,它允许您将Vue路由的组件按需加载。

安卓内存优化案例穷举

安卓内存优化是一个很重要的话题,有很多方面可以考虑,比如避免内存泄漏、减少内存抖动、优化图片加载、使用缓存和对象池等。下面我举一些代码案例,分别展示不合适的写法和高性能的写法。欢迎评论区留言指正和补充。1.避免使用枚举类型。枚举类型会占用更多的内存,因为它是一个类对象,而不是一个基本类型。如果需要定义一些常量,可以使用

【Python】pyecharts 模块 ① ( ECharts 简介 | pyecharts 简介 | pyecharts 中文网站 | pyecharts 画廊网站 | pyecharts 画 )

文章目录一、pyecharts模块1、ECharts简介2、pyecharts简介3、pyecharts中文网站4、pyecharts画廊网站5、pyecharts画廊用法pyecharts画廊网站:https://gallery.pyecharts.org/#/一、pyecharts模块1、ECharts简介ECha

u盘内容防止复制(U盘内数据防拷贝的方法)

随着科技的发展,U盘已经成为我们日常生活和工作中不可或缺的一部分。然而,U盘的普及也带来了一些问题,如数据泄露、病毒传播等。因此,保护U盘中的数据安全变得尤为重要。方法一:设置文件权限打开U盘,找到需要保护的文件或文件夹。右键点击文件或文件夹,选择“属性”。在弹出的属性窗口中,切换到“安全”选项卡。点击“编辑”按钮,打

解决vue项目导出当前页Table为Excel

解决vue项目中导出当前页表格为Excel表格的方案用到的技术:Vue2Element-uifile-saverxlsx1、创建vue项目,安装element-ui2、创建一个组件,组件内放入表格,和导出按钮<template><div><!--导出的按钮--><el-buttonsize="small"type="p

热文推荐