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

👍作者主页:进击的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);}//更新pospos = _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.mzph.cn/news/4966.shtml

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

相关文章

使用NVIDIA FX Composer验证多纹理合成效果

最近项目上有一个需求&#xff0c;需要将4张带透明通道纹理合成为一张&#xff0c;并且每张纹理指定一个全局透明度。由于纹理过多&#xff0c;合成效果无法保证&#xff0c;为了减少项目的风险&#xff0c;领导希望我先快速验证一下我们讨论的方法是否能完成项目的要求。因此我…

销售易的12年与七个瞬间

导读&#xff1a;企业级没有捷径 12年对一家企业意味着什么&#xff1f; 在消费互联网领域&#xff0c;12年足够长&#xff0c;短短几年内上市的故事过去屡见不鲜。在企业服务的toB领域&#xff0c;产业成熟和企业发展的时间维度被拉长&#xff0c;但故事同样精彩。 2023年7月1…

ylb-接口5产品详情

总览&#xff1a; 1、service处理&#xff08;根据产品id &#xff0c;查询产品信息&#xff09; 在api模块下service包&#xff0c;ProductService接口添加新方法&#xff08;根据产品id &#xff0c;查询产品信息queryById(Integer id)&#xff09;&#xff1a; package …

Python venv 和 virtualenv 虚拟环境的基本使用

1.前言 venv 和 virtualenv 都是搭建虚拟环境的工具&#xff0c;virtualenv 是第三方开源的&#xff0c;而 venv 作为 virtualenv 的一个子集自 Python3.3 开始集成到标准库中&#xff0c;在 virtualenv 的文档中可以看到他们的区别&#xff1a; 没有 app-data 种子方法&#…

Python爬虫——urllib_post请求百度翻译

post请求&#xff1a; post的请求参数&#xff0c;是不会拼接在url后面的&#xff0c;而是需要放在请求对象定制的参数中 post请求的参数需要进行两次编码&#xff0c;第一次urlencode&#xff1a;对字典参数进行Unicode编码转成字符串&#xff0c;第二次encode&#xff1a;将字…

isaac sim添加孔网格

isaac sim仿真和其它仿真实际上一样&#xff0c;对于孔的仿真&#xff0c;是没那么简单的 在此记录一下踩过的坑 1&#xff0c;首先&#xff0c;你需要在soildworks中将你的孔画出来&#xff0c;并导出stl 2&#xff0c;你可以在win10中使用3D画图查看孔的网格&#xff0c;看…

【css】用css样式快速写右上角badge徽标,颜色设置为渐变色

先看效果展示&#xff0c;已公开显示在图片卡片的右上角。 首先是dom代码&#xff1a;需要两个view或者div&#xff0c;public-badge是“已公开”那个矩形&#xff0c;show-signal是右边那个下三角&#xff0c;也就是阴影部分&#xff0c;这样看起来比较有立体感。 <view…

虚拟化技术及实时虚拟化概述

版权声明&#xff1a;本文为本文为博主原创文章&#xff0c;未经本人同意&#xff0c;禁止转载。如有问题&#xff0c;欢迎指正。博客地址&#xff1a;https://www.cnblogs.com/wsg1100/ 文章目录 一、前言二、分时系统三、虚拟化介绍四、虚拟化实现方式及分类模拟器Type2虚拟化…

欧姆龙PLC联网

一、设备信息确认 左上角的为PLC型号,如图该PLC型号为CP1H,不同型号的欧姆龙PLC通讯方面有什么差别呢? 通讯能力和方式不同: 有些型号PLC自带网口,有些则需要扩展(上图中右侧的两个红框内为后扩展的通讯口,扩展模块可以随意组合双网口,双232串口,双485串口都可以)…

JDBC编程连接MySQL数据库遇到的两个错误

在进行java与MySQL数据库进行连接的时候我遇到了两个报错&#xff0c;在一开始的时候遇到的报错是Access denied for user yulinlocalhost (using password: YES)&#xff0c;此时我在网络上搜索发现是密码出现错误的问题&#xff08;出现该问题确实是密码错误&#xff09;&…

【DevOps】Atlassian插件开发指南

本文以Bamboo插件开发为例&#xff0c;记录一下插件开发过程。 一、简介 Atlassian Bamboo 6.9.1 是一款持续集成和持续交付&#xff08;CI/CD&#xff09;工具&#xff0c;支持使用插件扩展其功能。如果需要开发自己的 Bamboo 插件并添加到 Bamboo 中&#xff0c;则可以参考…

设计模式——享元模式

享元模式 定义 享元模式&#xff08;Flyweight Pattern&#xff09;是池技术的重要实现方式。 使用共享对象可以有效地支持大量的细粒度对象。 优缺点、应用场景 优点 可以大大减少应用程序创建对象的数量&#xff0c;降低程序内存占用。 缺点 提高了系统的复杂度&…

spring-IOC

IOC容器 简介 IoC(Inversion of Control)控制反转&#xff0c;是一种基于面向对象编程法则的设计思想&#xff0c;它设计出的程序具有松耦合、更优良的特点。 IoC容器是Spring框架中重要的核心组件之一&#xff0c;贯穿了Spring从出生到成长的整个过程&#xff0c;Spring通过I…

零基础学习,轻松打造物业服务小程序

现如今&#xff0c;物业服务已经成为了人们生活中不可或缺的一部分。为了更好地满足人们对物业服务的需求&#xff0c;许多企业和个人开始开发物业服务小程序&#xff0c;以便提供更加便捷和高效的服务。然而&#xff0c;对于大多数人来说&#xff0c;搭建一个小程序可能需要一…

智能ai绘画软件帮你用科技点亮创意火花

李明&#xff1a;嘿&#xff0c;你听说过ai绘画软件吗&#xff1f;我最近对数字艺术产生了浓厚的兴趣 王磊&#xff1a;当然&#xff01;ai绘画软件真是太神奇了&#xff01;它可以将抽象的文字描述转换成惊人的艺术作品。 李明&#xff1a;是吗&#xff1f;它们绘制的效果怎…

数据库及数据表的相关操作(一)

目录 概念知识一、管理逻辑库与数据表二、常用数据类型和约束2.1 数字数据类型2.2 字符串数据类型2.3 日期数据类型2.4 字段约束 三、索引运行机制和使用原则3.1 创建索引3.2 添加与删除索引3.3 索引的使用原则 概念知识 关系型数据库&#xff1a; 使用了关系模型的数据库系统&…

深度学习——CNN卷积神经网络

基本概念 概述 卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种深度学习中常用于处理具有网格结构数据的神经网络模型。它在计算机视觉领域广泛应用于图像分类、目标检测、图像生成等任务。 核心思想 CNN 的核心思想是通过利用局部…

Linux内核源代码的目录结构包括部分:

内核核心代码&#xff1a;这部分代码包括内核的各个子系统和模块&#xff0c;如进程管理、内存管理、文件系统、网络协议栈等。这些代码构成了Linux内核的核心功能。 非核心代码&#xff1a;除了核心代码之外&#xff0c;还包括一些非核心的代码和文件&#xff0c;如库文件、固…

和chatgpt学架构03-引入UI框架(elment-plus)

目录 1 项目目录及文件的具体作用1.1 App.vue1.2 main.js的作用1.3 main.js什么时候被调用1.4 npm run serve干了什么事情1.5 package.json的作用 2 安装UI框架2.1 安装命令2.2 全局引入 3 启动工程总结 我们已经安装好了我们的vue脚手架&#xff0c;用vscode打开工程目录 要自…

【FPGA】基于C5的第一个SoC工程

文章目录 前言SoC的Linux系统搭建 前言 本文是在毕业实习期间学习FPGA的SoC开发板运行全连接神经网络实例手写体的总结。 声明&#xff1a;本文仅作记录和操作指南&#xff0c;涉及到的操作会尽量细致&#xff0c;但是由于文件过大不会分享文件&#xff0c;具体软件可以自行搜…