【1++的C++初阶】之vector

news2024/11/26 11:45:38

👍作者主页:进击的1++
🤩 专栏链接:【1++的C++初阶】

文章目录

  • 一,什么是vector?
  • 二,构造与析构
  • 三,vector迭代器的实现
  • 四,vector部分重要接口的实现

一,什么是vector?

vector是一种表示大小可变数组的容器。其本质就是动态数组,与我们前面写过的顺序表是大同小异的。与其他动态序列容器相比,vector的随机访问更加高效。但是,其插入与删除由于需要移动数据的原因,就显得效率较低。接下来我们将从其基本构成,各接口的实现原理以及易发生的问题等方面进行vector的学习!
在这里插入图片描述

二,构造与析构

与string不同的是,string一定是字符串,而vector中却可以存储多种类型的数据。这是模板就起了很大的作用。我们暂且将其数据类型叫做T。
vector采用的数据结构非常简单,线性连续空间,它以两个迭代器start,finish分别指向已经被使用了的空间。以end_of_storage来指向整块空间的尾端。
因此,其构造函数如下:

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

讲完了构造函数,我们再来讲讲拷贝构造。
先来传统写法的构造函数。

 vector(const vector<T>& v)
		{
			//深拷贝
			_start = new T[v.capacity()];
			//弊端:当有vector<vector<T>>这样的结构时,vector<T>进行的是浅拷贝。
		//	//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();

		}

这里需要注意的就是我们在注释中提到的,当vector中存储的数据是自定义类型涉及到空间时,如果仅仅使用memcpy,则将会出现两对象指向同一块空间。导致同一块空间被析构两次,就会报错。
在说明解决方法前,我们再补充一段代码


void swap(vector<T>& tmp)
		{
			std::swap(_start, tmp._start);
			std::swap(_finish, tmp._finish);
			std::swap(end_of_storage, tmp.end_of_storage);

		}
//赋值重载
vector<T>& operator=( vector<T> v)//在传参时就进行了深拷贝
		{
			swap(v);
			return *this;
		}

有了上述补充代码,我们就可以解决出现的问题了。
在这里插入图片描述
解决办法就是,让vector中存储的数据也进行深拷贝,便捷的方法就是利用遍历+其自己的赋值重载(自定义类型)。这样每个vector中的数据(自定义类型)都经过深拷贝,就不会发生同一空间被析构两次的情况。
我们再来学一种用迭代器进行初始化的构造构造。

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

		}

这里的迭代器也是使用了模板,使其能够用各种类型的迭代器进行初始化。

在上面我们讲述了拷贝构造的传统写法,接下来,我们在学习一种现代写法。

vector(const vector<T>& v)
			:_start(nullptr)
			,_finish(nullptr)
			,end_of_storage(nullptr)
		{
			
			vector<T> tmp(v.begin(), v.end());
			swap(tmp);

		}

其先是利用迭代器初始化构造出一个临时对象。然后将临时对象内的三个成员交换,由于其三个成员类型为迭代器(本质为T*)因此,交换就是原来tmp对象的空间,由*this维护,*this原来的空间则交给了tmp维护,并且,tmp是在函数内定义的,因此出了此函数,其生命周期结束,进行析构。**(要注意的是,在进行交换前,this对象要进行初始化,若不对其初始化,this中的成员是野指针,释放野指针指向的空间是错误的。)
在这里插入图片描述
最后,我们来讲一讲析构的实现----超简单的😎😎😎!
直接上代码😏😏😏

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

三,vector迭代器的实现

在第二小节我们就提到过其迭代器的本质为T*指针。
其迭代器主要作用就是进行遍历。
演示如下:

void test4()
	{
		vector<int> v;

		v.push_back(1);
		v.push_back(1);
		v.push_back(1);
		v.push_back(1);
		vector<int>::iterator it = v.begin();
		while (it!= v.end())
		{
			cout << (*it) << endl;
			++it;
		}
		
	}

在这里插入图片描述

除了上述遍历方法,还有一种范围for的遍历方法,其底层的实现就是用的迭代器。演示如下:

void test4()
	{
		vector<int> v;

		v.push_back(1);
		v.push_back(1);
		v.push_back(1);
		v.push_back(1);

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

在这里插入图片描述

四,vector部分重要接口的实现

reserve的实现

void reserve(size_t n)
		{
			size_t sz = size();
			if (n > capacity())
			{
				
				iterator tmp = new T[n];
				if (_start)
				{
					for (size_t i = 0; i < size(); i++)
					{
						tmp[i] = _start[i];
					}
					delete[]_start;					
				}
				_start = tmp;
				_finish = _start + sz;
				end_of_storage = _start + n;
			}
		}

在文章【1++的C++初阶】之内存管理中,我们有说过new,delete与malloc,free等的一个区别就是,前者能够自动调用构造与析构函数,因此我们在申请空间或者是扩容时,选择用new。当用new进行间接的扩容时,就涉及到了数据的拷贝,解决方法与拷贝构造相同。

resize的实现

void resize(size_t n, T val = T())
		{
			if (n > capacity())
			{
				reserve(n);
			}
			if (n > size() )
			{
				while(_finish<_start+n)
				{
					*_finish = val;
						++_finish;
				}
				
			}
			else
			{
				_finish = _start + n;
			}
		}

resize是调整其容器的大小,当其大小大于开辟空间的大小时,就进行扩容;并且,其还具有初始的功能。

insert实现

iterator insert(iterator pos, T val)
		{
			size_t len = pos - _start;
			assert(pos >= begin() && pos <= end());
			//扩容
			if (end_of_storage == _finish)
			{
				reserve(capacity() == 0 ? 4 : capacity() * 2);
			}
			//更新pos
			pos = _start + len;
			//移动数据
			iterator end = _finish-1;
			while ( end>= pos)
			{
				*(end + 1) = *end;
				end--;
			}
			*pos = val;
			_finish++;
			return pos;
		}

insert是将数据插入到pos位置,首先就要判断pos是否合法,然后要判断空间大小是否满足。**这里要注意的是当扩容后,pos就会失效,因为pos原来指向的空间已经不是我们要的空间了,因此,要更新pos。**在插入时,由于是连续的空间,因此要进行数据的移动。返回插入位置的迭代器。

erase的实现

iterator erase(iterator pos)
		{
			//不考虑缩容
			//移动数据
			assert(pos >= _start && pos < _finish);
			iterator begin = pos;
			while (begin < _finish)
			{
				*begin = *(begin + 1);
				begin++;
			}
			_finish--;
			return pos;
		}

在有些编译器下,会涉及到缩容,因此与insert一样,会面临迭代器失效的问题,因此要更新pos,但我们的实现不考虑缩容的情况。erase原理与insert相似,都要进行数据的挪动。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/771343.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

curl操作

下载路径&#xff1a;https://curl.se/windows/ 参考&#xff1a;https://blog.csdn.net/weixin_45191386/article/details/130652821 操作&#xff1a; curl http://localhost:8085/api/v1/aaa/bbbb/?ccc 652781344055627776

Android应用启动全流程分析(源码深度剖析)

作者&#xff1a;努比亚技术团队 源码来源&#xff1a;努比亚技术团队 1.前言 从用户手指点击桌面上的应用图标到屏幕上显示出应用主Activity界面而完成应用启动&#xff0c;快的话往往都不需要一秒钟&#xff0c;但是这整个过程却是十分复杂的&#xff0c;其中涉及了Android系…

Echarts折线图分割线颜色

直接上代码 splitLine: {show: true, // 是否显示分隔线。默认数值轴显示&#xff0c;类目轴不显示type: solid, // 坐标轴线线的类型&#xff08;solid&#xff0c;实线类型&#xff1b;dashed&#xff0c;虚线类型&#xff1b;dotted,点状类型&#xff09;lineStyle:…

一本通1910:【00NOIP普及组】计算器的改良题解

今天是编程集训的第二天&#xff0c;也是我来到CSDN整整1年。感谢所有阅读过我的文章的人&#xff0c;谢谢。 今天的比赛难度略低于昨天&#xff0c;但这道题也卡了我好久。 进入正题 题目&#xff1a; 题目描述&#xff1a; NCL是一家专门从事计算器改良与升级的实验室&a…

【软件测试】selenium中元素的定位

1.元素的定位 不管用那种方式&#xff0c;必须保证页面上该属性的唯一性 1.CSS 定位 CSS(Cascading Style Sheets)是一种语言&#xff0c;它被用来描述HTML 和XML 文档的表现。 CSS 使用选择器来为页面元素绑定属性。这些选择器可以被selenium 用作另外的定位策略CSS的获取可…

牛客小白月赛75题解

C 豆子 构造题 由构造公式知 第n级好豆子 第n-1级坏豆子^1 所以只需要构造一个豆子结构就行 第 i 级豆子 第 i 级豆子 第 i 级豆子 第 i 级豆子 第 i 级豆子 ^ 1 第i级豆子\begin{aligned} 第i级豆子 && 第i级豆子 \\ 第i级豆子 && 第i级豆子 \verb|^| 1 …

研究IOT,发现硬件和软件的结合才是解决方案,IOT的软件服务可以通过售卖硬件一起捆绑销售。而单纯做云服务比较难。

1&#xff0c;研究4G网卡&#xff0c;调研到DTU 关于DTU&#xff1a; DTU &#xff08;Data Transfer Unit&#xff09;是一种常见的的物联网通信终端产品&#xff0c;起到网关的作用&#xff0c;它一边通过串口或无线技术连接各种传感器、控制器、执行器等&#xff0c;另一边…

【Spring Boot学习一】创建项目 Spring Boot的配置文件

目录 一、安装插件 二、创建Spring Boot项目 1、创建项目 1.1 使用IDEA创建 1.2 网页版本创建 2、项目目录介绍与运行 三、Sping Boot的配置文件&#xff08;重点&#xff09; &#x1f337;1、.properties配置文件 &#xff08;1&#xff09;基础语法&#xff1a;Key …

【C++】将类对象转换成基本数据类型

2023年7月19日&#xff0c;周三晚上&#xff1a; 今天晚上看源码的时候&#xff0c;突然在某个类里面看到了“operator bool() const;”&#xff0c;我完全想不起来这是啥意思了&#xff0c;于是今晚重新学习了一下 目录 类型转换函数的定义类型转换函数的作用 类型转换函数的…

坐标系变换的坑

坐标系变换的坑 坐标系变换本来是很简单的事情&#xff0c;公式也很简单。但是卡了我很多天&#xff0c;原因是&#xff1a;两个坐标系的位姿&#xff0c;虽然都是右手系&#xff0c;但我的在顺时针旋转是yaw角是递增的&#xff0c;同事发给我的却是逆时针递减的。 理论上很简…

node自主学习——fs文件操作模块

目录 读文件 读文件是否成功的判定 写文件 写文件是否成功的判定 备注&#xff1a;VsCode、node v18.17.0 读文件 fs.readFile(文件路径, 编码格式&#xff08;可选&#xff09;, 回调函数)// 回调函数可以打印失败和成功的结果 // 若成功&#xff0c;err的值为null // 若…

自动化测试之数据驱动与关键字驱动

目录 1.录制/回放的神话 2.数据驱动的自动化测试框架 3.关键字驱动的自动化测试 初次接触自动化测试时&#xff0c;对数据驱动和关键字驱动不甚理解&#xff0c;觉得有点故弄玄须&#xff0c;不就是参数和函数其嘛&#xff01;其实其也体现了测试所不同与开发的一些特点&…

【JavaScript】Function的祖传方法call与apply

引言 内容速递 看了本文您能了解到的知识&#xff01; 在本篇文章中&#xff0c;将带你了解什么是call和apply&#xff0c;call和apply的用途、如何手写call和apply以及call和apply的使用场景。 1、什么是call和apply call()和apply()是JavaScript中的两个内置方法&#xff…

面试题:redis是单线程、StringBuffer是线程安全的

1、说明String 和StringBuffer的区别 类底层/ 可变&#xff1f;线程安全Stringfinal char[] 不可变是StringBuffer char[] 可变 是&#xff08;synchronized方法&#xff09;StringBuilder char[] 可变否 (4条消息) Java基础&#xff1a;String、StringBuffer、…

mcu 启动流程

MCU启动流程 MCU启动流程 MCU启动流程1 MCU的启动方式2 MCU程序启动执行过程3 启动过程的执行工作4 keil调式过程验证 1 MCU的启动方式 单片机的启动方式&#xff0c;以stm32为例&#xff0c;如下&#xff1a; 不同的下载方式对应的不同的启动方式&#xff0c;stm32主要有三种…

【最新教程】树莓派安装系统及VNC远程桌面连接

大家好&#xff0c;今天就不给大家介绍PYTHONL ,今天我作为一个刚入坑树莓派的小白&#xff0c;整理了一下自己安装树莓派的整个过程&#xff0c;分享给大家。 目录 树莓派 准备工作&#xff1a; 树莓派远程ssh失败access denied 原因&#xff1a; 树莓派系统安装 1、下载…

ImportError: cannot import name ‘imresize‘ from ‘scipy.misc‘

ImportError: cannot import name ‘imresize’ from ‘scipy.misc’ 今天在运行项目时发现了部分代码出现问题&#xff0c;报错图片如下&#xff1a; 通过了解得知&#xff0c;imresize已经被最新版本的Scipy库弃用了&#xff0c;所以在这里&#xff0c;处理这种错误可以选择…

ylb-接口6验证手机号是否注册

总览&#xff1a; 1、service处理 在api模块下service包&#xff0c;创建一个UserService接口&#xff1a;&#xff08;根据手机号查询数据queryByPhone(String phone)&#xff09; package com.bjpowernode.api.service;import com.bjpowernode.api.model.User; import co…

前端 | (六)CSS盒子模型 | 尚硅谷前端html+css零基础教程2023最新

学习来源&#xff1a;尚硅谷前端htmlcss零基础教程&#xff0c;2023最新前端开发html5css3视频 文章目录 &#x1f4da;元素的显示模式&#x1f407;CSS长度单位&#x1f407;元素的显示模式⭐️块元素&#xff08;block&#xff09;⭐️行内元素&#xff08;inline&#xff09…

网工内推 | 美图秀秀招网工,大专以上,15薪,NP认证优先

01 美图公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、美图大厦网络、分公司网络、IT相关项目的网络、办公内网服务器&#xff1b; 2、负责网络的设计、运行、管理和维护等工作&#xff1b; 3、负责远程办公环境的优化、运行、管理和维护工作&#xff1b; 4、…