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

STL?vector!!!

一、前言

        之前我们借助手撕string加深了类和对象相关知识,今天我们将一起手撕一个vector,继续深化类和对象、动态内存管理、模板的相关知识

二、vector相关的前置知识

        1、什么是vector?


        vector是一个STL库中提供的类模板,它是存储元素对象的顺序表,其中提供了一些有关增删查改的接口,它的特点是可以通过下标的方式在表中的任意位置进行读、写

        2、vector中的相关接口

        在本文接下来的部分会介绍vector的常用接口,事实上借助这些接口就可以解决平常所能遇到的大部分问题,如果还需要了解vector提供的更多接口及使用方法的话,可以跳转到一下网页:
        vector - C++ Referencehttps://legacy.cplusplus.com/reference/vector/vector/?kw=vector

三、手撕一个vector类

        1、成员变量与整体框架

        注意:之前的顺序表我们都是通过记录指针、元素个数和空间大小来完成的,顺序表的实现自然也可以这样,但是STL库中不是这样实现的,所以今天我们学习一下STL库中的实现方式

        

        上面的_start、_finish、_endofstorge分别代表着指向有效元素起始位置、终止位置的下一个位置和空间终止位置的迭代器,所以在上面我们已经定义了迭代器,事实上就是指针类型,这是由于顺序表的一大特点就是在内存中连续存储,所以可以直接使用未封装的指针;另一方面,我们在声明成员变量的同时都给了一个缺省值,这是由于它们都是指针类型,在初始化时我们都要先初始化成空指针再进行下一步操作,所以我们可以直接在这里给一个缺省值,这样避免了在初始化列表多次的显示初始化成空指针

        2、构造函数

        库中的函数头:
        

        以上的三个构造函数我们都会一一实现,在这里补充一点:在上面的构造函数中出现了"clloc",事实上,这是一个内存池,而后面所给的缺省值是STL库中提供的一个默认的内存池,它可以有效的提高开辟空间的时间消耗,但是比较复杂,所以在这里我们直接new空间,在之后,我们会专门的进行讲解

                (1).空构造:
                

                在这里实现的空构造是非常简单的,这是由于我们在声明时已经给了缺省值,但是该空构造是一定要写的,这是因为我们还要实现别的构造函数,这时候编译器就不在自动生成默认构造函数了

                (2).用n个元素对象进行初始化:
                

                在使用n个元素对象进行初始化时,我们在参数部分给了一个缺省值T(),很明显,这是一个匿名对象,同时调用了对应的默认构造函数,这是没有问题的,但是如果T是int、float等内置类型呢?事实上,这点不用担心,这是由于C++将这些内置类型都进行了升级,使它们可以象自定义类型一样调用默认构造函数,举个例子:如果T是int类型,那么此时T()就会返沪一个0进行初始化

                (3).使用一个迭代器区间进行初始化:
                

                在上面的构造函数中,我们再次使用了模板,但这里是函数模板,这是由于我们不仅要支持顺序表的迭代器类型初始化,还要支持其它类型的迭代器初始化

        3、返回顺序表一些性质的函数

                (1).size函数:返回此时vector中的元素个数

                库中的函数头:
                

                实现:
                

                (2).capacity函数:返回此时vector中的空间大小

                库中的函数头:
                

                实现:
                

        4、拷贝构造函数

        库中的函数头:

        

        实现:
        

        这里需要注意:我们不可以使用memcpy,这是由于memcpy会按字节将x的内容拷贝到_start,但如果T类型是动态开辟内存,也就是说是深拷贝的话,那么虽然vector整体进行了深拷贝,但是vector中的内容却只完成了浅拷贝,会出现深浅拷贝的问题,此时选择上面的方式就万无一失了,这要求元素对象重载了赋值运算符,这一点是必须的

        5、迭代器相关函数

                (1).begin函数:


                库中的函数头:
                

                begin函数进行了两个重载,分别是普通begin和const begin它们分别可以返回一个可读可写的迭代器和一个只读不写的迭代器,都指向vector的首元素位置:
                

                (2).end函数:


                库中的函数头:
                

                end函数仍然进行了两个重载,返回的迭代器都指向末尾元素的下一个位置:
                

        6、[]操作符重载

        库中的函数头:
        

        库中对[]操作符进行了两个重载,与上面的begin类似:
        

        库中对于很多类型进行了封装,事实上上面我们实现的与库中的本质是一样的

        7、交换函数

        库中的函数头:
        

        这里的交换一定是要涉及深拷贝的,在这里我们借用一下算法库中的swap函数,因为它恰好就是深拷贝:
        

        8、赋值运算符重载

        库中的函数头:
        

        在这里我们对该函数实现进行一点小改动,但是对于用户的使用来说是相同的:
        

        在上面的实现中,我们采用了传值传参,此时形参是实参的拷贝,拷贝会调用我们之前实现过的拷贝构造函数进行深拷贝,再调用swap函数,它也会进行深拷贝之下的交换,最终*this就变成了x的拷贝,最后x这一拷贝出作用域销毁,调用析构函数(后面会实现),进行了空间的释放

        9、开空间相关函数

                (1).reserve函数:会开辟指定大小的空间,如果原来有元素,会进行拷贝,否则不进行任何处理

                库中的函数头:
                

                实现:
                

                在上面我们又遇到了象拷贝构造函数同样的问题,所以再次使用了赋值运算符重载的方式进行处理

                (2).resize函数:会开辟指定大小的空间,用val进行初始化,缺省值为T()

                库中的函数头:
                

                实现:
                

                这里我们直接对之前的函数进行复用即可

        10、插入相关函数

                (1).insert函数:在迭代器指定的位置直接插入一个值,返回最后该位置的迭代器

                库中的函数头:
                

                实现:
                

                从上面的代码可以看出:在insert函数内部可能开辟空间,这时候pos就不是原来的pos了,所以在函数外部,传给过insert函数的迭代器是不能再次使用的,因为使用过的迭代器可能已经失效,这时候我们通过反回值的方式解决了这个问题,所以如果想再次使用的话,要接受函数的返回值

                (2).push_back函数:在vector尾部插入一个对象

                库中的函数头:
                

                实现:
                

                事实上在这个位置我们直接复用刚才写过的insert就非常方便

        11、删除相关函数

                (1).erase函数:删除迭代器指定位置的元素,返回该位置的迭代器

                库中的函数头:
                

                实现:
                

                erase所删除的位置有可能是最后一个,此时删除之后传入的迭代器·就失效了,所以要接收返回值并判断

                (2).pop_back函数

                库中的函数头:

                

                实现:
                

                直接复用刚才写过的erase函数即可

        12、析构函数

        由于析构函数的特殊性,这里就不提供库中的函数头了:

        

四、vector

        下面就是我们今天一起完成的vector了:
        

#include <iostream>
#include <cassert>
#include <algorithm>
using namespace std;
namespace bea
{template<class T>class vector{typedef T* iterator;typedef const T* const_iterator;public://空构造vector() {}//用n个元素对象进行初始化vector(size_t n, const T& val = T()){_start = new T[n + 5];for (size_t i = 0; i < n; i++){_start[i] = val;}_finish = _start + n;_endofstorge = _start + n + 4;}//使用一个迭代器区间进行初始化template<class InputIterator>vector(InputIterator first, InputIterator last){size_t n = last - first;_start = new T[n + 5];InputIterator it1 = first, it2 = _start;while (it1 < last){*it2 = *it1;it1++, it2++;}_finish = _start + n;_endofstorge = _start + n + 4;}//拷贝构造函数vector(const vector& x){size_t sz = x.size();_start = new T[sz + 5];for (size_t i = 0; i < sz; i++){_start[i] = x._start[i];}_finish = _start + sz;_endofstorge = _start + sz + 4;}//size函数size_t size() const{return _finish - _start;}//capacity函数size_t capacity() const{return _endofstorge - _start + 1;}//begin函数iterator begin(){return _start;}const_iterator begin() const{return _start;}//end函数iterator end(){return _finish;}const_iterator end() const{return _finish;}//[]操作符重载T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}//交换函数void swap(vector& x){std::swap(x._start, _start);std::swap(x._finish, _finish);std::swap(x._endofstorge, _endofstorge);}//赋值运算符重载vector& operator=(const vector x){swap(x);return *this;}//开空间相关函数void reserve(size_t n){size_t sz = size();if (n <= size()) return;iterator tmp = new T[n + 5];if (_start){for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}_finish = tmp + sz;_start = tmp;_endofstorge = tmp + n + 4;}//insert函数iterator insert(iterator pos, const T& val){assert(pos <= _finish);int n = pos - _start;if (capacity() < size() + 1){reserve(size() + 5);}pos = _start + n;iterator end = _finish - 1, next = _finish;while (next > pos){*next = *end;end--, next--;}*pos = val;_finish++;return pos;}void push_back(const T& val){insert(_finish, val);}void resize(size_t n, T& val = T()){vector(n, val);}//erase函数iterator erase(iterator pos){assert(pos < _finish);iterator end = pos + 1, front = pos;while (end < _finish){*front = *end;front++, end++;}_finish--;if (pos == _finish) return nullptr;else return pos;}//pop_back函数void pop_back(){erase(_finish - 1);}//析构函数~vector(){delete[] _start;_start = nullptr;_finish = nullptr;_endofstorge = nullptr;}private:iterator _start = nullptr;iterator _finish = nullptr;iterator _endofstorge = nullptr;};
}

五、结语

        这就是我们所实现的vector的全部内容了,我们的目的仍然是了解vector的用法、加深类和对象和模板等知识点的理解,感谢大家的阅读,欢迎各位于晏、亦菲和我一起交流、学习、进步!

                

               

相关文章:

STL?vector!!!

一、前言 之前我们借助手撕string加深了类和对象相关知识&#xff0c;今天我们将一起手撕一个vector&#xff0c;继续深化类和对象、动态内存管理、模板的相关知识 二、vector相关的前置知识 1、什么是vector&#xff1f; vector是一个STL库中提供的类模板&#xff0c;它是存储…...

从黔西游船侧翻事件看极端天气预警的科技防线——疾风气象大模型如何实现精准防御?

近日,贵州省黔西市一起载人游船侧翻事故令人痛心。调查显示,事发时当地突遇强风暴雨,水面突发巨浪导致船只失控。这一事件再次凸显:在极端天气频发的时代,传统“经验式防灾”已不足够,唯有依靠智能化的气象预警技术,才能筑牢安全底线。 极端天气预警的痛点:为什么传统方…...

LDO与DCDC总结

目录 1. 工作原理 2. 性能对比 3. 选型关键因素 4. 典型应用 总结 1. 工作原理 LDO LDO通过线性调节方式实现降压&#xff0c;输入电压需略高于输出电压&#xff08;压差通常为0.2-2V&#xff09;&#xff0c;利用内部PMOS管或PNP三极管调整压差以稳定输出电压。其结构简单…...

FastChat部署大模型

一、前提条件 1、系统环境&#xff08;使用的 autodl 算力平台&#xff09; 2、安装相关库 安装 modescope pip3 install -U modelscope # 或使用下方命令 # pip3 install -U modelscope -i https://mirror.sjtu.edu.cn/pypi/web/simple安装 fastchat git clone https://gi…...

智汇云舟亮相第二十七届北京科博会

5月8日&#xff0c;备受瞩目的第二十七届中国北京国际科技产业博览会&#xff08;以下简称&#xff1a;北京科博会&#xff09;在国家会议中心盛大开幕。作为我国科技领域的重要盛会&#xff0c;北京科博会汇聚了众多前沿科技成果与创新力量&#xff0c;为全球科技产业交流搭建…...

Redis最新入门教程

文章目录 Redis最新入门教程1.安装Redis2.连接Redis3.Redis环境变量配置4.入门Redis4.1 Redis的数据结构4.2 Redis的Key4.3 Redis-String4.4 Redis-Hash4.5 Redis-List4.6 Redis-Set4.7 Redis-Zset 5.在Java中使用Redis6.缓存雪崩、击穿、穿透6.1 缓存雪崩6.2 缓冲击穿6.3 缓冲…...

北斗三号手持终端设备功能与应用

北斗三号卫星系统是我国自主建设、独立运行的全球卫星导航系统。通过多颗不同轨道卫星组成的&#xff0c;这些卫星持续向地球发射携带精确时间和位置信息的信号。地面上的北斗手持终端接收到至少四颗卫星信号后&#xff0c;利用信号传播时间差&#xff0c;通过三角函数等算法&a…...

提升编程效率的利器:Zed高性能多人协作代码编辑器

在当今这个快节奏的开发环境中&#xff0c;一个高效、灵活的代码编辑器无疑对开发者们起着至关重要的支持作用。Zed&#xff0c;作为来自知名编辑器Atom和语法解析器Tree-sitter的创造者的心血之作&#xff0c;正是这样一款高性能支持多人合作的编辑神器。本文将带领大家深入探…...

【数据机构】2. 线性表之“顺序表”

- 第 96 篇 - Date: 2025 - 05 - 09 Author: 郑龙浩/仟墨 【数据结构 2】 文章目录 数据结构 - 2 -线性表之“顺序表”1 基本概念2 顺序表(一般为数组)① 基本介绍② 分类 (静态与动态)③ 动态顺序表的实现**test.c文件:****SeqList.h文件:****SeqList.c文件:** 数据结构 - 2 …...

Java如何获取电脑分辨率?

以下是一个 Java 程序示例&#xff0c;用于获取电脑的主屏幕分辨率&#xff1a; import java.awt.*; public class ScreenResolutionExample { public static void main(String[] args) { // 获取默认的屏幕设备 GraphicsDevice device GraphicsEnvironm…...

opencv中的图像特征提取

图像的特征&#xff0c;一般是指图像所表达出的该图像的特有属性&#xff0c;其实就是事物的图像特征&#xff0c;由于图像获得的多样性&#xff08;拍摄器材、角度等&#xff09;&#xff0c;事物的图像特征有时并不特别突出或与无关物体混杂在一起&#xff0c;因此图像的特征…...

dropout层

从你提供的图片来看&#xff0c;里面讨论了 Dropout 层&#xff0c;让我为你解释一下它的工作原理和作用。 Dropout 层是什么&#xff1f; Dropout 是一种常用的正则化技术&#xff0c;用于避免神经网络的 过拟合&#xff08;overfitting&#xff09;。过拟合是指模型在训练数…...

极狐GitLab 容器镜像仓库功能介绍

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 极狐GitLab 容器镜像库 (BASIC ALL) 您可以使用集成的容器镜像库&#xff0c;来存储每个极狐GitLab 项目的容器镜像。 要为您…...

【JVM-GC调优】

一、预备知识 掌握GC相关的VM参数&#xff0c;会基本的空间调整掌握相关工具明白一点&#xff1a;调优跟应用、环境有关&#xff0c;没有放之四海而皆准的法则 二、调优领域 内存锁竞争cpu占用io 三、确定目标 【低延迟】&#xff1a;CMS、G1&#xff08;低延迟、高吞吐&a…...

shopping mall(document)

shopping mall&#xff08;document&#xff09; 商城的原型&#xff0c;学习&#xff0c;优化&#xff0c;如何比别人做的更好&#xff0c;更加符合大众的习惯 抄别人会陷入一个怪圈&#xff0c;就是已经习惯了&#xff0c;也懒了&#xff0c;也不带思考了。 许多产品会迫于…...

qiankun微前端任意位置子应用

qiankun微前端任意位置子应用 主项目1、安装qiankun2、引入注册3、路由创建4、路由守卫 二、子项目1、安装sh-winter/vite-plugin-qiankun2、main.js配置3、vite.config.js配置 三、问题解决 主项目 1、安装qiankun npm i qiankun -S2、引入注册 创建存放子应用页面 //whpv…...

【LeetCode Solutions】LeetCode 176 ~ 180 题解

CONTENTS LeetCode 176. 第二高的薪水&#xff08;SQL 中等&#xff09;LeetCode 177. 第 N 高的薪水&#xff08;SQL 中等&#xff09;LeetCode 178. 分数排名&#xff08;SQL 中等&#xff09;LeetCode 179. 最大数&#xff08;中等&#xff09;LeetCode 180. 连续出现的数字…...

前端面试每日三题 - Day 29

这是我为准备前端/全栈开发工程师面试整理的第29天每日三题练习&#xff1a; ✅ 题目1&#xff1a;Web Components技术全景解析 核心三要素 Custom Elements&#xff08;自定义元素&#xff09; class MyButton extends HTMLElement {constructor() {super();this.attachShado…...

第十五章,SSL VPN

前言 IPSec 和 SSL 对比 IPSec远程接入场景---client提前安装软件&#xff0c;存在一定的兼容性问题 IPSec协议只能够对感兴趣的流量进行加密保护&#xff0c;意味着接入用户需要不停的调整策略&#xff0c;来适应IPSec隧道 IPSec协议对用户访问权限颗粒度划分的不够详细&…...

spring5.x讲解介绍

Spring 5.x 是 Spring Framework 的重要版本升级&#xff0c;全面拥抱现代 Java 技术栈&#xff0c;其核心改进涵盖响应式编程、Java 8支持、性能优化及开发模式创新。以下从特性、架构和应用场景三个维度详细解析&#xff1a; 一、核心特性与架构改进 Java 8 全面支持 Spring …...

荣耀A8互动娱乐组件部署实录(第3部分:控制端结构与房间通信协议)

作者&#xff1a;曾在 WebSocket 超时里泡了七天七夜的苦命人 一、控制端总体架构概述 荣耀A8控制端主要承担的是“运营支点”功能&#xff0c;也就是开发与运营之间的桥梁。它既不直接参与玩家行为&#xff0c;又控制着玩家的行为逻辑和游戏规则触发机制。控制端的主要职责包…...

levelDB的数据查看(非常详细)

起因:.net大作业天气预报程序(WPF)答辩时&#xff0c;老师问怎么维持数据持久性的&#xff0c;启动时加载的数据存在哪里&#xff0c;我明白老师想考的应该是json文件的解析&#xff08;正反&#xff09;&#xff0c;半天没答上来存那个文件了&#xff08;老师默认这个文件是自…...

在Fiddler中添加自定义HTTP方法列并高亮显示

在Fiddler中添加自定义HTTP方法列并高亮显示 Fiddler 是一款强大的 Web 调试代理工具&#xff0c;允许开发者检查和操作 HTTP 流量。一个常见需求是自定义 Web Sessions 列表&#xff0c;添加显示 HTTP 方法&#xff08;GET、POST 等&#xff09;的列&#xff0c;并通过颜色区…...

基于公共卫生大数据收集与智能整合AI平台构建测试:从概念到实践

随着医疗健康数据的爆发式增长,如何有效整合、分析和利用这些数据已成为公共卫生领域的重要挑战。传统方法往往难以应对数据的复杂性、多样性和海量性,而人工智能技术的迅猛发展为解决这些挑战提供了新的可能性。基于数据整合与公共卫生大数据的AI平台旨在构建一个全面的生态…...

clahe算法基本实现

一、背景介绍 图像算法处理中&#xff0c;经常需要遇到图像对比度调整的情况&#xff0c;CLAHE(Contrast Limited Adaptive Histogram Equalization)则是一种基于直方图&#xff0c;使用非常普遍的图像对比度调整算法。 关于这个算法的介绍有很多&#xff0c;基本原理这些&…...

python打卡day20

特征降维------特征组合&#xff08;以SVD为例&#xff09; 知识点回顾&#xff1a; 奇异值的应用&#xff1a; 特征降维&#xff1a;对高维数据减小计算量、可视化数据重构&#xff1a;比如重构信号、重构图像&#xff08;可以实现有损压缩&#xff0c;k 越小压缩率越高&#…...

如何使用极狐GitLab 软件包仓库功能托管 ruby?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 软件包库中的 Ruby gems (BASIC ALL) WARNING:Ruby gems 软件包库正在开发中&#xff0c;由于功能有限&#xff0c;尚未准备好…...

数字化转型-4A架构之数据架构

系列文章 数字化转型-4A架构&#xff08;业务架构、应用架构、数据架构、技术架构&#xff09; 数字化转型-4A架构之业务架构 数字化转型-4A架构之应用架构 数据架构 Data Architecture&#xff08;DA&#xff09; 1. 定义 数据架构&#xff0c;是组织管理数据资产的科学之…...

React 第三十七节 Router 中 useOutlet Hook的使用介绍以及注意事项

React Router 中的 useOutlet 是 v6 版本新增的 Hook&#xff0c;用于在父路由组件中访问当前嵌套的子路由元素。它提供了比 <Outlet> 组件更灵活的控制方式&#xff0c;适合需要根据子路由状态进行动态处理的场景。 一、useOutlet的基本用法 import { useOutlet } fro…...

u-boot学习笔记(四)

文章目录 cmd/sub_cmd/exit.cdo_exit()exit.c可提供的命令及使用方式&#xff1a; ext2.cdo_ext2ls()do_ext2load()ext2.c可提供的命令及使用方式&#xff1a; ext4.cdo_ext4_size()do_ext4_load()do_ext4_ls()do_ext4_write()ext4.c可提供的命令及使用方式&#xff1a; fastbo…...