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

【C++初阶】--- vector容器功能模拟实现

1.什么是vector?

在 C++ 里,std::vector 是标准模板库(STL)提供的一个非常实用的容器类,它可以看作是动态数组
在这里插入图片描述

2.成员变量

iterator _start;:指向 vector 中第一个元素的指针。
iterator _finish;:指向 vector 中最后一个元素的下一个位置的指针。
iterator _end_of_storage;:指向 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;
}

3.构造函数

3.1默认构造

因为三个成员变量都有缺省值,我们只需要显示写默认构造即可,他们会在初始化链表处初始化。

//写法1:
vector()
{}
//写法2:
vector() = default;//C++11支持强制生成默认构造

3.2拷贝构造

  1. 调用 reserve 函数,提前为新 vector 对象分配足够的内存空间,其大小和 v 的元素数量相同,此步骤可以避免后续添加元素时的频繁扩容。
  2. 借助范围 for 循环遍历 v 中的每个元素,使用引用 auto& 避免不必要的拷贝(特别是当元素为自定义类型时)
  3. 对 v 中的每个元素,调用 push_back 函数将其添加到新 vector 对象的末尾。
//拷贝构造
vector(const vector<T>& v)
{//提前开好空间reserve(v.size());//如果元素是自定义类型,用引用可以减少拷贝for (auto& ch : v){//尾插数据push_back(ch);}
}

3.3迭代器构造函数

迭代器构造函数需要我们传两个迭代器,我们使用范围for将元素尾插至新构造的vector对象中,构造的范围是[first,last)
注意:类模板的成员函数,也可以是函数模板,我们可以将这个迭代器构造函数写成模板,优点是可以用不同的类构造vector对象,前提是元素类型需相同,如:int

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

3.4半缺省构造函数

我们可以通过半缺省构造函数构造一个有n个val值得vector对象

  1. 使用resver提前开好空间,避免后续插入元素时频繁扩容
  2. 使用for循环尾插n个值为val的元素,如果不传参使用的是缺省值T()
  3. 对于内置类型(如 int、double、char 等),T() 会进行值初始化。对于数值类型,会初始化为 0;对于指针类型,会初始化为 nullptr。
  4. 对于自定义类型,T() 会调用该类型的默认构造函数。如果没有显式定义默认构造函数,编译器会自动生成一个(前提是该类没有其他带参数的构造函数

注意:我们使用半缺省构造函数的时候传参需要注意,如下:如果不显示第一个参数是size_t,编译器会优先调用更符合的构造函数,即会上面的迭代器构造函数

//u表示10是size_t类型
vector<int> v1(10u,1);
//用n个val进行构造,T()是匿名对象
vector(size_t n, const T& val = T())
{reserve(n);for (size_t i = 0; i < n; i++){//如果用这种,_finish记得++//*_finish = val;//_finish++;push_back(val);}
}

4.析构函数

三个指针指向同一块空间的不同位置,使用delete释放的时候我们需要使用指向vector中第一个元素的指针,同一块空间不能进行多次释放。

//析构
~vector()
{if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}
}

5.iterators

5.1begin()/end()

//普通对象使用
iterator begin()
{return _start;
}iterator end()
{return _finish;
}//const对象使用
const_iterator begin() const
{return _start;
}const_iterator end() const
{return _finish;
}

6.内联函数

6.1size()

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

6.2capacity()

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

6.3empty()

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

6.4clear()

void clear()
{_finish = _start;
}

6.5swap()

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

6.7=运算符重载

普通写法:

  1. 先清除当前vector对象中的所有元素
  2. 提前开头看见,避免后续频繁扩容
  3. 使用范围for依次将元素尾插至当前vector对象
//赋值运算符重载
vector<T>& operator=(const vector<T>& v)
{if (this != &v){//先清理原先数据clear();//提前开好空间reserve(v.size());//如果数据是自定义类型可以减少拷贝for (auto& ch : v){push_back(ch);}}return *this;
}

现代写法:

//赋值运算符重载,现代写法
//这里是拷贝,不是引用,且不加const
vector<T>& operator=(vector<T> v)
{swap(v);return *this;
}

6.8[]运算符重载

//普通对象使用
T& operator[](size_t i)
{//i不能越界assert(i < size());return _start[i];
}//const对象使用
const T& operator[](size_t i) const
{//i不能越界assert(i < size());return _start[i];
}

7.尾插/尾删元素

7.1push_back()

  1. 判断空间是否已满,已满需进行扩容操作,使用三木操作符,如果当前vector对象空间对空,扩容至4个元素,不为空则选择2倍扩容。
  2. 尾插元素,_finish指针向后移动一位
//尾插
//如果是自定义类型,用引用可以减少拷贝
void push_back(const T& x)
{//扩容if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = x;_finish++;
}

7.2pop_back()

  1. 判断当前vector对象中是否还剩余元素,元素为0则断言失败
  2. 还有元素则将_finish指针前移一位
//尾删
void pop_back()
{//判空assert(!empty());_finish--;
}

8.在pos位置插入删除元素

8.1insert()

  1. 判断pos位置的有效性,可插入范围为[_start,_finish]
  2. 判断空间是否足够,不够则进行扩容操作
    注意:如果进行扩容操作,则会造成迭代器失效,需要更新下迭代器
  3. 将pos位置及之后的数据向后移动一位
  4. 在pos位置插入元素,返回pos位置的迭代器
//在pos位置插入数据
iterator insert(iterator pos, const T& x)
{//pos有效性assert(pos >= _start && pos <= _finish);//扩容if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());//扩容后pos迭代器会失效,需要更新一下pos = _start + len;}//将pos及之后的数据往后移动一位iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;return pos;
}

8.2erase()

  1. 判断pos位置的有效性,可删除范围为[_start,_finish)
  2. 将pos之后的数据向前移动一位,将pos位置的数据进行覆盖
  3. 别忘了将_finish指针也前移一位
//删除pos位置的数据
template<class T>
void vector<T>::erase(iterator pos)
{//pos有效性assert(pos >= _start && pos < _finish);//向前移动数据iterator it = pos + 1;while (it != end()){*(it - 1) = *it;it++;}--_finish;
}

9.空间大小和数据大小调整

9.1resize()

将vector对象中的数据个数调整至n个,如果n小于当前元素个数,将当前元素个数调整为n,如果n大于当前元素个数,使用val对其进行填充。

//调整长度
template<class T>
void vector<T>::resize(size_t n, T val)
{//n小于长度,缩减长度if (n < size()){_finish = _start + n;}//n大于长度,在后面补元素else{//可能需要扩容reserve(n);//从原数据结尾开始补while (_finish < _start + n){//*_finish = val;//_finish++;push_back(val);}}
}

9.2reserve()

将空间大小扩容至n,如果n小于当前空间大小,不进行操作和改变

  1. 保存旧空间大小old_size,否则后续:
    _start = tmp;
    _finish = tmp + size();
    而size()是_finish-_start,从而_finish = tmp + size()=_start+_finish-_start=_finish
  2. new新空间,大小为n
  3. 将原对象内容进行深拷贝,不能使用memcpy进行拷贝
    在这里插入图片描述
  4. 释放原空间,更新成员变量
template<class T>
void vector<T>::reserve(size_t n)
{//n大于空间大小才扩容if (n > capacity()){size_t old_size = size();//new个新空间T* tmp = new T[n];//memcpy对于内置类型是深拷贝,对于自定义类型是浅拷贝,所以不能用memcpy//memcpy(tmp, _start, size() * sizeof(T));for (size_t i = 0; i < size(); i++){tmp[i] = _start[i];}//销毁旧空间数据delete[] _start;_start = tmp;_finish = tmp + old_size;_end_of_storage = tmp + n;}
}

10打印vector对象内容

C++规定:没有实例化的类模板里取东西,编译器不能区分这里的const_vector是类型还是变量,在前面加上typename表示取的是类型。
当然也可以使用auto自动识别类型。

//打印顺序表的模板
template<class T>
void print_vector(const vector<T>& v)
{//auto it = v.begin();typename vector<T>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;/*	for (auto ch : v){cout << ch << " ";}cout << endl;*/
}

通用打印模板:

//通用打印模板
template<class Container>
void print_vector(const Container& v)
{auto it = v.begin();while (it != v.end()){cout << *it << " ";it++;}cout << endl;//或者//for (auto ch : v)//{//	cout << ch << " ";//}//cout << endl;
}

相关文章:

【C++初阶】--- vector容器功能模拟实现

1.什么是vector&#xff1f; 在 C 里&#xff0c;std::vector 是标准模板库&#xff08;STL&#xff09;提供的一个非常实用的容器类&#xff0c;它可以看作是动态数组 2.成员变量 iterator _start;&#xff1a;指向 vector 中第一个元素的指针。 iterator _finish;&#x…...

函数式编程在 Java:Function、BiFunction、UnaryOperator 你真的会用?

大家好&#xff0c;我是你们的Java技术博主&#xff01;今天我们要深入探讨Java函数式编程中的几个核心接口&#xff1a;Function、BiFunction和UnaryOperator。很多同学虽然知道它们的存在&#xff0c;但真正用起来却总是不得要领。这篇文章将带你彻底掌握它们&#xff01;&am…...

Elasticsearch 学习规划

Elasticsearch 学习规划 明确学习目标与动机 场景化需求分析 - **S**&#xff1a;掌握Elasticsearch架构体系&#xff0c;熟练使用Elasticsearch 进行数据分析,Elasticsearch结合java 项目落地案例 - **M**&#xff1a;搜索和Elasticsearch相关GitHub项目 - **A**&#xff1a;每…...

【AI提示词】Emoji风格排版艺术与设计哲学

提示说明 Emoji风格排版艺术与设计哲学。 提示词 请使用 Emoji 风格编辑以下段落&#xff0c;该风格以引人入胜的标题、每个段落中包含表情符号和在末尾添加相关标签为特点。请确保保持原文的意思。使用案例&#xff08;春日穿搭&#xff09; &#x1f338; 2025春季穿搭灵…...

LVM 扩容详解

目录 一、LVM扩容 1. 查看磁盘分区情况&#xff1a; 2. 查看pv、vg、lv 情况 3. 将新硬盘分区初始化 4. 将初始化后的分区添加到VG中 5. 查看逻辑卷的设备路径 6. VG分配给lv 二、扩展文件系统 1.确认文件系统类型 三、检验 一、LVM扩容 1. 查看磁盘分区情况&#xff1a; …...

STM32 低功耗模式下 RTC唤醒 和 PA0唤醒 的配合使用

STM32 低功耗模式不同唤醒源的配合使用 by 矜辰所致前言 关于 STM32 如何实现低功耗模式&#xff0c;我之前写过一篇文章&#xff1a; STM32 使用 STM32CubeMX HAL库实现低功耗模式 各种休眠模式如何实现文中已经讲得很清楚了&#xff0c;但是作为教学文章&#xff0c;文…...

QML 弹窗控件:Popup的基本用法与样式

目录 引言相关阅读Popup基本属性工程结构示例实现Main.qml - 主界面SimplePopup.qml - 简单弹窗ModalPopup.qml - 模态弹窗CustomPopup.qml - 自定义样式弹窗AnimatedPopup.qml - 带动画的弹窗 总结工程下载 引言 在现代图形用户界面(GUI)开发中&#xff0c;弹窗(Popup)是一种…...

MCP基础学习三:MCP客户端开发与工具集成

MCP客户端开发与工具集成 文章目录 MCP客户端开发与工具集成一, 学习目标二, 学习内容1. MCP客户端与服务端的通信方式1.1 通信原理1.2 通信实现分析 2. 如何开发MCP工具并集成到客户端2.1 工具开发流程2.2 工具实现示例2.3 客户端集成 3. 如何集成外部API到MCP客户端3.1 集成流…...

NSS#Round30 Web

小桃的PHP挑战 <?php include jeer.php; highlight_file(__FILE__); error_reporting(0); $A 0; $B 0; $C 0;//第一关 if (isset($_GET[one])){$str $_GET[str] ?? 0;$add substr($str, 0, 1); $add;if (strlen($add) > 1 ) {$A 1;} else {echo $one; } } else…...

POSIX线程(pthread)库:线程的终止与管理

在POSIX线程&#xff08;pthread&#xff09;库中&#xff0c;线程的终止和管理涉及多个关键函数。以下是关于线程终止的pthread系列函数的详细介绍&#xff1a; 1. pthread_exit&#xff1a;线程主动退出 ✨ 功能&#xff1a; 允许线程主动终止自身&#xff0c;并返回一个退出…...

解决 IntelliJ IDEA 中 Maven 项目左侧项目视图未显示顶层目录问题的详细步骤说明

以下是解决 IntelliJ IDEA 中 Maven 项目左侧项目视图未显示顶层目录问题的详细步骤说明&#xff1a; 1. 切换项目视图模式 默认情况下&#xff0c;IDEA 的项目视图可能处于 Packages 模式&#xff0c;仅显示代码包结构&#xff0c;而非物理目录。 操作步骤&#xff1a; 点击…...

408 计算机网络 知识点记忆(6)

前言 本文基于王道考研课程与湖科大计算机网络课程教学内容&#xff0c;系统梳理核心知识记忆点和框架&#xff0c;既为个人复习沉淀思考&#xff0c;亦希望能与同行者互助共进。&#xff08;PS&#xff1a;后续将持续迭代优化细节&#xff09; 往期内容 408 计算机网络 知识…...

Multisim 仿真 DC Sweep 双源嵌套扫描嵌套

Multisim仿真工具箱里头有DC Sweep分析方法&#xff0c;分析中可以对两个源参数扫描分析 类似于编程的循环嵌套&#xff1a; for( Source 2 : start value; Increment; Source 2 : stop value;) {for( Source 1 : start value; Increment; Source 2 : stop value;){... //…...

Python | 绘制黑底的水平空间分布图

写在前面 记录一下之前为了做PPT汇报画的一张图&#xff0c;虽然最后也没怎么用上。为了方面以后再需要&#xff0c;这里把代码和数据整理放到GitHub上。有兴趣的也可以玩玩 需要的数据 风场数据可以从ERA5的官网下载 https://cds.climate.copernicus.eu/datasets/reanalys…...

京东与喜茶关系破裂:切断所有合作 禁止进入办公场所

快科技4月10日消息&#xff0c;据报道&#xff0c;京东集团近日被曝出内部下发全员禁令&#xff0c;全面封杀喜茶产品进入办公区域。 据知情人士透露&#xff0c;京东人力行政部门发布的通知明确规定&#xff1a;全国各职场禁止与喜茶品牌开展任何形式的合作&#xff1b;员工不…...

LangChain-记忆系统 (Memory)

记忆系统是LangChain的核心组件之一&#xff0c;允许应用程序记住和使用过去的交互信息。本文档详细介绍了LangChain中的记忆组件类型、工作原理和使用场景。 概述 在构建对话式AI应用时&#xff0c;能够记住上下文和之前的交互至关重要。LangChain的记忆组件负责&#xff1a…...

stm32开发(一)之创建工程与第一个程序

ps&#xff1a; 开发模式 1.基于库函数&#xff08;标准库&#xff09; 推荐 2.基于HAL库 图形化 3.基于寄存器 最直接 一、创建工程 1、打开keil5 new Project->路径->命名->保存 2、选择型号&#xff1a;stm32f103c8 初始创建工程我们不使用快捷项目建设 …...

【电商】基于LangChain框架将多模态大模型连接数据库实现精准识别

1. LangChain框架 LangChain是一个用于构建基于大语言模型的应用框架&#xff0c;通过模块化设计简化了LLM与外部工具&#xff0c;数据源和复杂逻辑的集成。 连接能力 将多个LLM调用&#xff0c;工具调用或者数据处理步骤串联成工作流 数据感知 外部数据集成 支持连接数据…...

鸿蒙HarmonyOS埋点SDK,ClkLog适配鸿蒙埋点分析

ClkLog埋点分析系统&#xff0c;是一种全新的、开源的洞察方案&#xff0c;它能够帮助您捕捉每一个关键数据点&#xff0c;确保您的决策基于最准确的用户行为分析。技术人员可快速搭建私有的分析系统。 ClkLog鸿蒙埋点SDK通过手动埋点的方式实现HarmonyOS 原生应用的前端数据采…...

详解 kotlin 相对 Java 特有的关键字及使用

文章目录 1. val 和 var2. fun3. when4. is 和 !is5. lateinit6. by7. reified8. companion 本文首发地址&#xff1a;https://h89.cn/archives/366.html 最新更新地址&#xff1a;https://gitee.com/chenjim/chenjimblog Kotlin 在兼容Java的基础上&#xff0c;引入了许多特有…...

湘西的未来交响曲

故事摘要 在中国湖南湘西的未来&#xff0c;苗族文化与高科技完美融合&#xff0c;构建出一个既传统又现代的世界。晨曦中的沱江&#xff0c;悬浮的吊脚楼面带着品位独特的织锦纹样&#xff0c;展示了令人惊叹的未来建筑美学。独特的工坊技术使得每件首饰都能感知佩戴者的情感&…...

STM32_HAL库提高中断执行效率

目录 中断流程分析我的解决办法优缺点 大家都在说STM32 HAL 库中断效率低下。具体哪里不行&#xff1f;如何优化&#xff1f; 我手里的项目要用到多个定时器TIM6、TIM7、TIM9、TIM10、TIM11、TIM12、TIM13&#xff0c;在处理这些定时器中断的时候&#xff0c;也发现了这个问题。…...

软件系统安全设计方案,信息化安全建设方案(Word原件)

1.1 总体设计 1.1.1 设计原则 1.2 物理层安全 1.2.1 机房建设安全 1.2.2 电气安全特性 1.2.3 设备安全 1.2.4 介质安全措施 1.3 网络层安全 1.3.1 网络结构安全 1.3.2 划分子网络 1.3.3 异常流量管理 1.3.4 网络安全审计 1.3.5 网络访问控制 1.3.6 完…...

什么是微前端?有什么好处?有哪一些方案?

微前端&#xff08;Micro Frontends&#xff09; 微前端是一种架构理念&#xff0c;借鉴了微服务的思想&#xff0c;将一个大型的前端应用拆分为多个独立、自治的子应用&#xff0c;每个子应用可以由不同团队、使用不同技术栈独立开发和部署&#xff0c;最终聚合为一个整体产品…...

电机 断路器选型

一、断路器额定电流计算基础 ‌电机额定电流估算‌ 三相380V电机额定电流可按经验公式快速计算&#xff1a; I电机≈2P(P为功率/kW)I电机​≈2P(P为功率/kW) 例如&#xff1a;7.5kW电机额定电流约15A‌。 ‌断路器倍数选择范围‌ ‌通用标准‌&#xff1a;1.2~2.5倍电机额定电…...

Web前端之Vue+Element实现表格动态不同列合并多行、localeCompare、forEach、table、push、sort、Map

MENU 效果图公共数据数据未排序时&#xff08;需要合并的行数据未处于相邻位置&#xff09;固定合并行&#xff08;写死&#xff09;动态合并行方法&#xff08;函数&#xff09;执行 效果图 公共数据 Html <el-table :data"tableData" :span-method"chang…...

【教学类-102-07】剪纸图案全套代码07——Python点状虚线优化版本+制作1图2图6图

背景需求: 我觉得这个代码里面的输入信息分离太远(42行和241行),想重新优化一下 【教学类-102-05】蛋糕剪纸图案(留白边、沿线剪)04——Python白色(255)图片转为透明png再制作“点状边框和虚线边框”-CSDN博客文章浏览阅读864次,点赞14次,收藏27次。【教学类-102-0…...

Redis与Lua原子操作深度解析及案例分析

一、Redis原子操作概述 Redis作为高性能的键值存储系统&#xff0c;其原子性操作是保证数据一致性的核心机制。在Redis中&#xff0c;原子性指的是一个操作要么完全执行&#xff0c;要么完全不执行&#xff0c;不会出现部分执行的情况。 Redis原子性的实现原理 单线程模型&a…...

QT中怎么隐藏或显示最大化、最小化、关闭按钮

文章目录 方法一&#xff1a;通过代码动态设置1、隐藏最大化按钮2、隐藏最小化按钮3、隐藏关闭按钮方法 1&#xff1a;移除 WindowCloseButtonHint方法 2&#xff1a;使用 Qt::CustomizeWindowHint 并手动控制按钮 4、同时隐藏最大化和最小化按钮5、同时隐藏最大化和关闭按钮6、…...

OpenSceneGraph相机系统

一、相机的核心原理 Open Scene Graph&#xff08;OSG&#xff09;中相机的核心原理围绕‌视图变换‌和‌投影变换‌展开&#xff0c;结合场景图的层次化结构实现三维空间的动态渲染。 1、视图变换&#xff08;View Transformation&#xff09; &#xff09;视图矩阵的作用‌…...