当前位置: 首页 > news >正文

【STL】vector常见用法及模拟实现(附源码)

目录

      • 前言
      • 1. vector介绍及使用
        • 1.1vector的介绍
        • 1.2 vector的使用
          • 1.2.1 构造函数
        • 1.2.2 vector对象遍历
        • 1.2.3 reserve和resize
        • 1.2.4 insert和erase
      • 2. vector模拟实现
        • 2.1 vector迭代器失效问题
        • 2.2 模拟实现reserve函数浅拷贝问题
        • 2.3模拟实现源码
          • 2.3.1 vector.h
          • 2.3.2 test.cpp

前言

这篇文章我们来学习一下STL容器里的vector,我们先来学习一下它的使用,然后对vector进行模拟实现。

1. vector介绍及使用

1.1vector的介绍

vector文档介绍

vector是一个大小可以更改的数组序列容器。

在这里插入图片描述
其实这里可以简单认为vector就是之前数据结构学的顺序表。

1.2 vector的使用

vector提供的接口跟string是非常相似的,所以经过前面string的学习,再学习vector成本降低了很多。
在这里插入图片描述
下面我们来介绍一下常用接口

1.2.1 构造函数

在这里插入图片描述
首先看第一个:
在这里插入图片描述
这个是用来传空间配置器的,我们可以认为这个就是无参的构造函数,构造一个空的vector

注意:
vector是一个类模板,类模板实例化只能显式实例化,即需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可。
类模板不是真正的类,其实例化的结果才是真正的类。

在这里插入图片描述

在这里插入图片描述
这个就是支持用n个val构造一个vector对象。
在这里插入图片描述

在这里插入图片描述
这个就是支持迭代器区间构造,也不难理解我们来给大家演示一下:
在这里插入图片描述

在这里插入图片描述这个就是拷贝构造了
在这里插入图片描述

1.2.2 vector对象遍历

在这里插入图片描述
vector也重载了[]这里可以使用for循环遍历:
在这里插入图片描述
也可以使用迭代器,也就是支持范围for:
在这里插入图片描述

1.2.3 reserve和resize

首先我们来看一下vector的扩容机制:

#include <iostream>
#include <vector>
using namespace std;
int main()
{// 测试vector的默认扩容机制size_t sz;vector<int> v;sz = v.capacity();cout << "making v grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}return 0;
}

这里g++下是二倍扩:
在这里插入图片描述

当我们知道需要多少空间,直接用reserve把空间开好,就可以减少频繁扩容的一个消耗。
在这里插入图片描述
在这里插入图片描述
确定知道需要用多少空间,reserve可以缓解vector增容的代价缺陷问题

我们再来看一下resize():
在这里插入图片描述
resize在开空间的同时还会进行初始化,当然如果传的n比size小,那它还会删除多余的数据。
在这里插入图片描述

1.2.4 insert和erase

与string相比vector只支持我们去传迭代器和迭代器区间了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. vector模拟实现

2.1 vector迭代器失效问题

会引起其底层空间改变的操作,都有可能导致迭代器失效,比如:resize、reserve、insert、assign、push_back等。
出错原因:
以上操作,都有可能会导致vector扩容,迭代器失效,实际就是迭代器底层对应指针所指向的空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)

这里我们举个简单的例子,以下代码用于输出v1中所有偶数:

int main()
{vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(6);for (auto e : v1){cout << e << " ";}cout << endl;auto it = v1.begin();while(it != v1.end())//错误代码{if(*it % 2 == 0){v1.erase(it);}it++;}// while (it != v1.end())// {//     if (*it % 2 == 0)//     {//         it = v1.erase(it);//     }//     else//     {//         ++it;//     }// }
}

在这里插入图片描述
这里程序会报错出现段错误。实际上这里是因为是因为erase删除pos位置元素后,pos位置之后的元素会往前搬移,他没有接收返回值而是一味的进行++操作导致程序越界奔溃

2.2 模拟实现reserve函数浅拷贝问题

这里主要出现错误的原因就是内部使用了memcpy来拷贝数据。

  1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中
  2. 如果拷贝的是内置类型的元素,memcpy既高效又不会出错

但如果拷贝的是自定义类型元素,并且
自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝

我们这里以vector< string >为例:
在这里插入图片描述

2.3模拟实现源码
2.3.1 vector.h
#include<iostream>
#include<assert.h>
using namespace std;namespace w
{template<class T>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(size_t n, const T& val = T()){resize(n, val);}vector(int n, const T& val = T()){resize(n, val);}// [first, last)template<class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(){}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();_endofstorage = _start + v.capacity();}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endofstorage, v._endofstorage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}~vector(){if (_start){delete[] _start;_start = _finish = _endofstorage = nullptr;}}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);for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}void resize(size_t n, const T& val = T()){if (n < size()){_finish = _start + n;}else{reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}void push_back(const T& x){insert(end(), x);}void pop_back(){erase(--end());}size_t capacity() const{return _endofstorage - _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];}iterator insert(iterator pos, const T& x){assert(pos >= _start && pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;size_t newcapacity = capacity() == 0 ? 4 : capacity() * 2;reserve(newcapacity);// 解决pos迭代器失效问题pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);iterator it = pos + 1;while (it != _finish){*(it - 1) = *it;++it;}--_finish;return pos;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorage = nullptr;};}
2.3.2 test.cpp
#include "vector.h"
void test_vector1(){w:: vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout<<endl;for (size_t i = 0; i < v1.size(); i++){v1[i]++;}for (auto e : v1){cout << e << " ";}cout << endl;}void test_vector2(){w ::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(5);v1.push_back(5);v1.push_back(5);for (auto e : v1){cout << e << " ";}cout << endl;v1.insert(v1.begin(), 100);for (auto e : v1){cout << e << " ";}cout << endl;}int main()
{test_vector2();return 0;
}

相关文章:

【STL】vector常见用法及模拟实现(附源码)

目录 前言1. vector介绍及使用1.1vector的介绍1.2 vector的使用1.2.1 构造函数 1.2.2 vector对象遍历1.2.3 reserve和resize1.2.4 insert和erase 2. vector模拟实现2.1 vector迭代器失效问题2.2 模拟实现reserve函数浅拷贝问题2.3模拟实现源码2.3.1 vector.h2.3.2 test.cpp 前言…...

深度学习保姆级教学

文章目录 前言1.深度学习概论2.神经网络1.基础原理2.损失函数3.SoftMax4.前向传播5.反向传播1.反向传播介绍 6 卷积神经网络应用1.检测任务2.超分辨率重构3.医学检测4.无人驾驶5. 人脸识别 6.卷积网络和传统区别7.卷积神经网络1.卷积做了什么&#xff1f;2.节点网络1.Alexnet2.…...

计算机视觉的优势和挑战

计算机视觉&#xff08;CV&#xff09;是一项快速发展的技术&#xff0c;它具有许多优势和挑战。以下是一些可能的例子&#xff1a; 优势&#xff1a; 1. 自动化&#xff1a;CV技术可以自动化任务&#xff0c;例如图像分类、目标检测和跟踪&#xff0c;从而提高生产力和减少人…...

群晖管家+内网穿透实现公网远程访问本地黑群晖

白嫖怪狂喜&#xff01;黑群晖也能使用群晖管家啦&#xff01; 文章目录 白嫖怪狂喜&#xff01;黑群晖也能使用群晖管家啦&#xff01;1.使用环境要求&#xff1a;2.下载安装群晖管家app3.随机地址登陆群晖管家app4.固定地址登陆群晖管家app 自己组装nas的白嫖怪们虽然也可以通…...

Essential C++【读书笔记 思考总结】

本篇博客是学习过程中的笔记、思考和总结。原文链接&#xff1a; 3 泛型编程风格 Generic Programming3.1 指针的算术运算3.2 了解 Iterator&#xff08;泛型指针&#xff09;3.3 所有容器的共通操作 3 泛型编程风格 Generic Programming STL的主要组件&#xff1a;Container&…...

深度学习实战基础案例——卷积神经网络(CNN)基于Xception的猫狗识别|第2例

文章目录 一、环境准备二、数据预处理三、构建模型四、实例化模型五、训练模型5.1 构建训练函数5.2 构建测试函数5.3 开始正式训练 六、可视化精度和损失七、个体预测总结 今天使用轻量级的一个网络Xception做一个简单的猫狗识别案例&#xff0c;我的环境具体如下&#xff1a; …...

Linux Systemd 配置开机自启

博文目录 文章目录 Systemd操作方式配置方式配置示例参考 Systemd Systemd 是一个用于启动、管理和监控 Linux 系统的初始化系统。它是许多现代 Linux 发行版中默认的初始化系统&#xff0c;取代了传统的 SysVinit 和 Upstart。 Systemd 的引入在 Linux 社区引起了一些争议&…...

华为云云耀云服务器L实例评测|轻量级应用服务器对决:基于 fio 深度测评华为云云耀云服务器L实例的磁盘性能

本文收录在专栏&#xff1a;#云计算入门与实践 - 华为云 专栏中&#xff0c;本系列博文还在更新中 相关华为云云耀云服务器L实例评测文章列表如下&#xff1a; 华为云云耀云服务器L实例评测 | 从零开始&#xff1a;云耀云服务器L实例的全面使用解析指南华为云云耀云服务器L实…...

卸载Visual Studio 2010学习版 —— 卸载VCExpress

目录 最初安装Visual Studio 2010学习版是因为计算机二级 C语言考试而装&#xff0c;现如今考完试后便可卸载掉了&#xff0c;安装简便而卸载却没有uninstall.exe文件。故本文提供卸载方式。 进入到程序目录&#xff0c;找到setup.exe文件&#xff0c;也可以在程序目录搜索set…...

react的状态管理简单钩子方法

1.recoil useProvider文件: import { atom, useRecoilState } from recoil;const initState atom({key: initState,default: {state: [],}, })// 将业务逻辑拆分到一个单独文件中&#xff0c;方便进行状态管理 export interface StateProps {id: number;text: string;isFini…...

【Git】轻松学会 Git:深入理解 Git 的基本操作

文章目录 前言一、创建 Git 本地仓库1.1 什么是仓库1.2 创建本地仓库1.3 .git 目录结构 二、配置 Git三、认识 Git 的工作区、暂存区和版本库3.1 什么是 Git 的工作区、暂存区和版本库3.2 工作区、暂存区和版本库之间的关系 四、添加文件4.1 添加文件到暂存区和版本库中的命令4…...

什么是HTTP头部(HTTP headers)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 理解 HTTP 头部&#xff08;HTTP Headers&#xff09;⭐ HTTP 头部的分类⭐ HTTP 头部的应用⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#x…...

SpringCloud Alibaba 入门到精通 - Sentinel

SpringCloud Alibaba 入门到精通 - Sentinel 一、基础结构搭建1.父工程创建2.子工程创建 二、Sentinel的整合SpringCloud1.微服务可能存在的问题2.SpringCloud集成Sentinel搭建Dashboard3 SpringCloud 整合Sentinel 三、服务降级1 服务降级-Sentinel2 Sentinel 整合 OpenFeign3…...

【深度学习实验】前馈神经网络(三):自定义多层感知机(激活函数logistic、线性层算Linear)

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 构建数据集 2. 激活函数logistic 3. 线性层算子 Linear 4. 两层的前馈神经网络MLP 5. 模型训练 一、实验介绍 本实验实现了一个简单的两层前馈神经网络 激活函数…...

HJ68 成绩排序

描述 给定一些同学的信息&#xff08;名字&#xff0c;成绩&#xff09;序列&#xff0c;请你将他们的信息按照成绩从高到低或从低到高的排列,相同成绩 都按先录入排列在前的规则处理。 例示&#xff1a; jack 70 peter 96 Tom 70 smith 67 从高到低…...

FPGA——UART串口通信

文章目录 前言一、UART通信协议1.1 通信格式2.2 MSB或LSB2.3 奇偶校验位2.4 UART传输速率 二、UART通信回环2.1 系统架构设计2.2 fsm_key2.3 baud2.4 sel_seg2.5 fifo2.6 uart_rx2.7 uart_tx2.8 top_uart2.9 发送模块时序分析2.10 接收模块的时序分析2.11 FIFO控制模块时序分析…...

华为云Stack的学习(七)

八、华为云Stack存储服务介绍 1.云硬盘EVS 云硬盘&#xff08;Elastic Volume Service&#xff0c;EVS&#xff09;&#xff0c;又名磁盘&#xff0c;是一种虚拟块存储服务&#xff0c;主要为ECS&#xff08;Elastic Cloud Server&#xff09;和BMS&#xff08;Bare Metal Se…...

安装k8s集群

一、前置环境配置 安装两台centos 实验环境&#xff0c;一台pc配有docker环境&#xff0c;有两个centsos7容器&#xff0c;其中一个容器作为master&#xff0c;一个作为node。如果master与node都是用默认端口&#xff0c;会存在冲突&#xff0c;所以在此基础上做细微的调整。…...

C++中编写没有参数和返回值的函数

C中编写没有参数和返回值的函数 返回值为 void 函数不需要将值返回给调用者。为了告诉编译器函数不返回值&#xff0c;返回类型为 void。例如&#xff1a; #include <iostream>// void means the function does not return a value to the caller void printHi() {std…...

SWC 流程

一个arxml 存储SWC &#xff08;可以存多个&#xff0c;也可以一个arxml存一个SWC&#xff09;一个arxml 存储 composition &#xff08;只能存一个&#xff09;一个arxml 存储 system description (通过import dbc自动生成system) 存储SWC和composition的arxml文件分开&#…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...

AWSLambda之设置时区

目标 希望Lambda运行的时区是东八区。 解决 只需要设置lambda的环境变量TZ为东八区时区即可&#xff0c;即Asia/Shanghai。 参考 使用 Lambda 环境变量...

盲盒一番赏小程序:引领盲盒新潮流

在盲盒市场日益火爆的今天&#xff0c;如何才能在众多盲盒产品中脱颖而出&#xff1f;盲盒一番赏小程序给出了答案&#xff0c;它以创新的玩法和优质的服务&#xff0c;引领着盲盒新潮流。 一番赏小程序的最大特色在于其独特的赏品分级制度。赏品分为多个等级&#xff0c;从普…...