【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拷贝构造
- 调用 reserve 函数,提前为新 vector 对象分配足够的内存空间,其大小和 v 的元素数量相同,此步骤可以避免后续添加元素时的频繁扩容。
- 借助范围 for 循环遍历 v 中的每个元素,使用引用 auto& 避免不必要的拷贝(特别是当元素为自定义类型时)。
- 对 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对象
- 使用resver提前开好空间,避免后续插入元素时频繁扩容
- 使用for循环尾插n个值为val的元素,如果不传参使用的是缺省值T()
- 对于内置类型(如 int、double、char 等),T() 会进行值初始化。对于数值类型,会初始化为 0;对于指针类型,会初始化为 nullptr。
- 对于自定义类型,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=运算符重载
普通写法:
- 先清除当前vector对象中的所有元素
- 提前开头看见,避免后续频繁扩容
- 使用范围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()
- 判断空间是否已满,已满需进行扩容操作,使用三木操作符,如果当前vector对象空间对空,扩容至4个元素,不为空则选择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()
- 判断当前vector对象中是否还剩余元素,元素为0则断言失败
- 还有元素则将_finish指针前移一位
//尾删
void pop_back()
{//判空assert(!empty());_finish--;
}
8.在pos位置插入删除元素
8.1insert()
- 判断pos位置的有效性,可插入范围为[_start,_finish]
- 判断空间是否足够,不够则进行扩容操作
注意:如果进行扩容操作,则会造成迭代器失效,需要更新下迭代器 - 将pos位置及之后的数据向后移动一位
- 在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()
- 判断pos位置的有效性,可删除范围为[_start,_finish)
- 将pos之后的数据向前移动一位,将pos位置的数据进行覆盖
- 别忘了将_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小于当前空间大小,不进行操作和改变
- 保存旧空间大小old_size,否则后续:
_start = tmp;
_finish = tmp + size();
而size()是_finish-_start,从而_finish = tmp + size()=_start+_finish-_start=_finish - new新空间,大小为n
- 将原对象内容进行深拷贝,不能使用memcpy进行拷贝

- 释放原空间,更新成员变量
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? 在 C 里,std::vector 是标准模板库(STL)提供的一个非常实用的容器类,它可以看作是动态数组 2.成员变量 iterator _start;:指向 vector 中第一个元素的指针。 iterator _finish;&#x…...
函数式编程在 Java:Function、BiFunction、UnaryOperator 你真的会用?
大家好,我是你们的Java技术博主!今天我们要深入探讨Java函数式编程中的几个核心接口:Function、BiFunction和UnaryOperator。很多同学虽然知道它们的存在,但真正用起来却总是不得要领。这篇文章将带你彻底掌握它们!&am…...
Elasticsearch 学习规划
Elasticsearch 学习规划 明确学习目标与动机 场景化需求分析 - **S**:掌握Elasticsearch架构体系,熟练使用Elasticsearch 进行数据分析,Elasticsearch结合java 项目落地案例 - **M**:搜索和Elasticsearch相关GitHub项目 - **A**:每…...
【AI提示词】Emoji风格排版艺术与设计哲学
提示说明 Emoji风格排版艺术与设计哲学。 提示词 请使用 Emoji 风格编辑以下段落,该风格以引人入胜的标题、每个段落中包含表情符号和在末尾添加相关标签为特点。请确保保持原文的意思。使用案例(春日穿搭) 🌸 2025春季穿搭灵…...
LVM 扩容详解
目录 一、LVM扩容 1. 查看磁盘分区情况: 2. 查看pv、vg、lv 情况 3. 将新硬盘分区初始化 4. 将初始化后的分区添加到VG中 5. 查看逻辑卷的设备路径 6. VG分配给lv 二、扩展文件系统 1.确认文件系统类型 三、检验 一、LVM扩容 1. 查看磁盘分区情况: …...
STM32 低功耗模式下 RTC唤醒 和 PA0唤醒 的配合使用
STM32 低功耗模式不同唤醒源的配合使用 by 矜辰所致前言 关于 STM32 如何实现低功耗模式,我之前写过一篇文章: STM32 使用 STM32CubeMX HAL库实现低功耗模式 各种休眠模式如何实现文中已经讲得很清楚了,但是作为教学文章,文…...
QML 弹窗控件:Popup的基本用法与样式
目录 引言相关阅读Popup基本属性工程结构示例实现Main.qml - 主界面SimplePopup.qml - 简单弹窗ModalPopup.qml - 模态弹窗CustomPopup.qml - 自定义样式弹窗AnimatedPopup.qml - 带动画的弹窗 总结工程下载 引言 在现代图形用户界面(GUI)开发中,弹窗(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线程(pthread)库中,线程的终止和管理涉及多个关键函数。以下是关于线程终止的pthread系列函数的详细介绍: 1. pthread_exit:线程主动退出 ✨ 功能: 允许线程主动终止自身,并返回一个退出…...
解决 IntelliJ IDEA 中 Maven 项目左侧项目视图未显示顶层目录问题的详细步骤说明
以下是解决 IntelliJ IDEA 中 Maven 项目左侧项目视图未显示顶层目录问题的详细步骤说明: 1. 切换项目视图模式 默认情况下,IDEA 的项目视图可能处于 Packages 模式,仅显示代码包结构,而非物理目录。 操作步骤: 点击…...
408 计算机网络 知识点记忆(6)
前言 本文基于王道考研课程与湖科大计算机网络课程教学内容,系统梳理核心知识记忆点和框架,既为个人复习沉淀思考,亦希望能与同行者互助共进。(PS:后续将持续迭代优化细节) 往期内容 408 计算机网络 知识…...
Multisim 仿真 DC Sweep 双源嵌套扫描嵌套
Multisim仿真工具箱里头有DC Sweep分析方法,分析中可以对两个源参数扫描分析 类似于编程的循环嵌套: for( Source 2 : start value; Increment; Source 2 : stop value;) {for( Source 1 : start value; Increment; Source 2 : stop value;){... //…...
Python | 绘制黑底的水平空间分布图
写在前面 记录一下之前为了做PPT汇报画的一张图,虽然最后也没怎么用上。为了方面以后再需要,这里把代码和数据整理放到GitHub上。有兴趣的也可以玩玩 需要的数据 风场数据可以从ERA5的官网下载 https://cds.climate.copernicus.eu/datasets/reanalys…...
京东与喜茶关系破裂:切断所有合作 禁止进入办公场所
快科技4月10日消息,据报道,京东集团近日被曝出内部下发全员禁令,全面封杀喜茶产品进入办公区域。 据知情人士透露,京东人力行政部门发布的通知明确规定:全国各职场禁止与喜茶品牌开展任何形式的合作;员工不…...
LangChain-记忆系统 (Memory)
记忆系统是LangChain的核心组件之一,允许应用程序记住和使用过去的交互信息。本文档详细介绍了LangChain中的记忆组件类型、工作原理和使用场景。 概述 在构建对话式AI应用时,能够记住上下文和之前的交互至关重要。LangChain的记忆组件负责:…...
stm32开发(一)之创建工程与第一个程序
ps: 开发模式 1.基于库函数(标准库) 推荐 2.基于HAL库 图形化 3.基于寄存器 最直接 一、创建工程 1、打开keil5 new Project->路径->命名->保存 2、选择型号:stm32f103c8 初始创建工程我们不使用快捷项目建设 …...
【电商】基于LangChain框架将多模态大模型连接数据库实现精准识别
1. LangChain框架 LangChain是一个用于构建基于大语言模型的应用框架,通过模块化设计简化了LLM与外部工具,数据源和复杂逻辑的集成。 连接能力 将多个LLM调用,工具调用或者数据处理步骤串联成工作流 数据感知 外部数据集成 支持连接数据…...
鸿蒙HarmonyOS埋点SDK,ClkLog适配鸿蒙埋点分析
ClkLog埋点分析系统,是一种全新的、开源的洞察方案,它能够帮助您捕捉每一个关键数据点,确保您的决策基于最准确的用户行为分析。技术人员可快速搭建私有的分析系统。 ClkLog鸿蒙埋点SDK通过手动埋点的方式实现HarmonyOS 原生应用的前端数据采…...
详解 kotlin 相对 Java 特有的关键字及使用
文章目录 1. val 和 var2. fun3. when4. is 和 !is5. lateinit6. by7. reified8. companion 本文首发地址:https://h89.cn/archives/366.html 最新更新地址:https://gitee.com/chenjim/chenjimblog Kotlin 在兼容Java的基础上,引入了许多特有…...
湘西的未来交响曲
故事摘要 在中国湖南湘西的未来,苗族文化与高科技完美融合,构建出一个既传统又现代的世界。晨曦中的沱江,悬浮的吊脚楼面带着品位独特的织锦纹样,展示了令人惊叹的未来建筑美学。独特的工坊技术使得每件首饰都能感知佩戴者的情感&…...
STM32_HAL库提高中断执行效率
目录 中断流程分析我的解决办法优缺点 大家都在说STM32 HAL 库中断效率低下。具体哪里不行?如何优化? 我手里的项目要用到多个定时器TIM6、TIM7、TIM9、TIM10、TIM11、TIM12、TIM13,在处理这些定时器中断的时候,也发现了这个问题。…...
软件系统安全设计方案,信息化安全建设方案(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 完…...
什么是微前端?有什么好处?有哪一些方案?
微前端(Micro Frontends) 微前端是一种架构理念,借鉴了微服务的思想,将一个大型的前端应用拆分为多个独立、自治的子应用,每个子应用可以由不同团队、使用不同技术栈独立开发和部署,最终聚合为一个整体产品…...
电机 断路器选型
一、断路器额定电流计算基础 电机额定电流估算 三相380V电机额定电流可按经验公式快速计算: I电机≈2P(P为功率/kW)I电机≈2P(P为功率/kW) 例如:7.5kW电机额定电流约15A。 断路器倍数选择范围 通用标准:1.2~2.5倍电机额定电…...
Web前端之Vue+Element实现表格动态不同列合并多行、localeCompare、forEach、table、push、sort、Map
MENU 效果图公共数据数据未排序时(需要合并的行数据未处于相邻位置)固定合并行(写死)动态合并行方法(函数)执行 效果图 公共数据 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作为高性能的键值存储系统,其原子性操作是保证数据一致性的核心机制。在Redis中,原子性指的是一个操作要么完全执行,要么完全不执行,不会出现部分执行的情况。 Redis原子性的实现原理 单线程模型&a…...
QT中怎么隐藏或显示最大化、最小化、关闭按钮
文章目录 方法一:通过代码动态设置1、隐藏最大化按钮2、隐藏最小化按钮3、隐藏关闭按钮方法 1:移除 WindowCloseButtonHint方法 2:使用 Qt::CustomizeWindowHint 并手动控制按钮 4、同时隐藏最大化和最小化按钮5、同时隐藏最大化和关闭按钮6、…...
OpenSceneGraph相机系统
一、相机的核心原理 Open Scene Graph(OSG)中相机的核心原理围绕视图变换和投影变换展开,结合场景图的层次化结构实现三维空间的动态渲染。 1、视图变换(View Transformation) )视图矩阵的作用…...
