CD43.vector模拟实现(2)

目录

1.拷贝构造函数

写法1

写法2

测试代码

调试找bug

解决方法:修改拷贝构造函数

测试代码

2.operator[ ]

测试代码

1.没有const修饰

2.有const修饰

3.insert

迭代器失效问题


承接CD42.vector模拟实现(1)文章

1.拷贝构造函数

设置start、finish和end_of_storage这几个参数就行,注意是深拷贝!

写法1

vector(const vector<value_type>& x):start(0), finish(0), end_of_storage(0)
{start = new T[x.capacity()];memmove(start, x.start, x.size()*sizeof(value_type));finish = start + x.size();end_of_storage = start + x.capacity();
}

注:new的参数可以为capacity,也可以为size,这个C++标准没有规定,空间可以不一样,但是有效元素必须一样

写法2

复用reserve和memmove函数

这个代码有问题:

vector(const vector<value_type>& x):start(0), finish(0), end_of_storage(0)
{reserve(x.capacity());memmove(start, x.start, x.size() * sizeof(value_type));
}

测试代码

void const_vector_print(const mystl::vector<int> v)
{for (size_t i = 0;i < v.size(); i++)std::cout << v[i] << " ";
}void test6()
{mystl::vector<int> v;v.push_back(1); v.push_back(2);v.push_back(3); const_vector_print(v);return;
}

运行结果:什么都没有打印

调试找bug

什么都没有打印,可以判定没有进入循环,

下断点到循环,看看情况:

start和finish的地址一样,v.size()计算出来为0,没有进入循环,可以断定拷贝构造函数出了问题,

下断点到拷贝构造函数,再次调试:

x.capacity()计算出来是4,进入reserve函数内部:

对空的vector进行reserve,看以下分析图:

解决方法:修改拷贝构造函数

reserve没有更新finish,那就手动更新finish

vector(const vector<value_type>& x):start(0), finish(0), end_of_storage(0)
{reserve(x.capacity());finish = start + x.size();memmove(start, x.start, x.size() * sizeof(value_type));
}

而且标准库也是这样实现的:

运行结果:

同理,reserve函数也要修改:

void  reserve(size_type n)
{if (n > capacity()){T* tmp = new T[n];size_t len = size();//delete前先保存元素的个数!bool flag = false;if (size() == 0){flag = true;len = n;}memmove(tmp,start , size()* sizeof(value_type));delete[] start;if (flag)//如果vector在什么元素都没有{start = finish = tmp;}else{start = tmp;finish = start + len;}end_of_storage = start + n;}
}

测试代码

void test4()
{mystl::vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);mystl::vector<int> v2(v1);for (auto& a:v2)std::cout << a << " ";
}

运行结果:

2.operator[ ]

参数保持一样的类型:

注意到返回类型被重定义过,因此先进行重定义:

typedef value_type& reference;
typedef const value_type& const_reference;

必须保证提供的n是合法的,换句话说,n<size(),可以使用assert断言

reference operator[] (size_type n)
{assert(n < size());return *(start + n);//也可以写成start[n]
}const_reference operator[] (size_type n) const
{assert(n < size());return *(start + n);//也可以写成start[n]
}

测试代码

1.没有const修饰

void test5()
{mystl::vector<int> v;v.push_back(1); v[0]++;v.push_back(2); v[1]++;v.push_back(3); v[2]++;for (auto& a : v)std::cout << a << std::endl;return;
}

运行结果:

2.有const修饰

void const_vector_print(const mystl::vector<int> v)
{for (size_t i = 0;i < v.size(); i++)std::cout << v[i] << " ";
}void test6()
{mystl::vector<int> v;v.push_back(1); v.push_back(2);v.push_back(3); const_vector_print(v);return;
}

运行结果:

3.insert

参数保持一样的类型,为了简单起见,这里只实现第一个

首先要断言,position必须合法:

assert(position >= start && position <= finish);

插入前先看看是否需要扩容,可以直接借用CD42.vector模拟实现(1)文章的push_back函数的代码:

if (finish == nullptr)reserve(4);
if (finish == end_of_storage)reserve(capacity() * 2);

和CD38.【C++ Dev】string类的模拟实现(2)文章类似的思路,先移动再插入

迭代器失效问题

如果insert的返回值是void,

void insert(iterator position, const value_type& val)
{assert(position >= start && position <= finish);if(finish == nullptr)reserve(4);if (finish == end_of_storage)reserve(capacity() * 2);iterator i = finish-1;while (i >= position){*(i+1) = *i;i--;}*position = val;finish++;
}

头插:

void test7()
{mystl::vector<int> v;v.push_back(1);v.push_back(2);v.insert(v.begin(), 3);return;
}

 

尾插:

void test7()
{mystl::vector<int> v;v.push_back(1);v.push_back(2);v.insert(v.end(), 3);return;
}

中间位置插入:

void test7()
{mystl::vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.insert(v.begin() + 1, 4);return;
}

貌似没有问题,但是如果是这个测试代码:

void test7()
{mystl::vector<int> v;v.push_back(1);auto pos = v.begin();for (size_t i = 2; i <= 8; i++)v.insert(pos, i);return;
}

运行结果会出问题: 

引出迭代器失效问题

pos记录的是原来v的start的值,如果v扩容,start的值会改变,但pos的值没有更新,而且原先的内存空间被释放会导致非法访问,因此再执行v.insert(pos, i);就会出问题(即pos为野指针)

解决方法:扩容后更新pos的值,STL的解决方法:返回值为iterator

 

iterator insert(iterator position, const value_type& val)
{assert(position >= start && position <= finish);if(finish == nullptr)reserve(4);if (finish == end_of_storage)reserve(capacity() * 2);iterator i = finish-1;while (i >= position){*(i+1) = *i;i--;}*position = val;finish++;return start;
}

注:position不能引用传参,有可能insert的第一个参数会做算术运算,例如:
 

v.insert(pos+20, i);

测试代码: 

void test7()
{mystl::vector<int> v;v.push_back(1);auto pos = v.begin();for (size_t i = 2; i <= 8; i++)pos=v.insert(pos, i);return;
}

验证pos是否更新:
原先:

扩容更新后:

运行结果:退出代码为0

当然CD42.vector模拟实现(1)文章的push_back可以复用insert的代码

1.如果不接收insert的返回值,扩容要慎重,修改可能会报错,因为不一定扩容,所以不一定失效;

2.insert以后就不要使用原本定义的迭代器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/908128.shtml

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

相关文章

【C/C++】入门grpc的idl

文章目录 grpc idl 简单介绍1. 文件结构组织规范文件命名包结构&#xff1a;推荐&#xff1a;一个文件只定义一个 service&#xff0c;如果 service 很复杂&#xff0c;可拆分多个 proto 文件。 2. 消息定义规范命名风格字段编号&#xff1a;示例&#xff1a; 3. 服务与 RPC 设…

安全-JAVA开发-第二天

Web资源访问的流程 由此可见 客户访问JAVA开发的应用时 会先通过 监听器&#xff08;Listener&#xff09;和 过滤器&#xff08;Filter&#xff09; 今天简单的了解下这两个模块的开发过程 监听器&#xff08;Listener&#xff09; 主要是监听 我们触发了什么行为 并进行反应…

使用 Ansys Q3D 进行电容提取

精确的电容提取在高速和 RF 设计中至关重要。虽然简单的公式可以提供一个很好的起点&#xff0c;但它们往往无法捕捉 fringing fields 和 layout-dependent parasitics 的影响。在本博客中&#xff0c;我们演示了如何使用Ansys Q3D Extractor来计算电容值&#xff0c;从基本的平…

卡西欧模拟器:Windows端功能强大的计算器

引言 大家还记得初中高中时期用的计算器吗&#xff1f;今天给大家分享的就是一款windows端的卡西欧计算器。 软件介绍 大家好&#xff0c;我是逍遥小欢。 CASIO fx-9860G是一款功能强大的图形计算器&#xff0c;适用于数学、科学和工程计算。以下是其主要功能和特点的详细介…

【Bluedroid】蓝牙启动之gatt_init 流程源码解析

本文围绕Android蓝牙协议栈中 GATT(通用属性配置文件)模块的初始化函数gatt_init展开,深入解析其核心实现逻辑与关键步骤。通过分析gatt_init及其关联子函数(如L2CA_RegisterFixedChannel、gatt_profile_db_init、EattExtension::Start等),以及相关数据结构(如tGATT_CB控…

Vue 3 中ref 结合ts 获取 DOM 元素的实践指南。

文章目录 前言一、为什么需要为 ref 添加类型&#xff1f;二、基本用法&#xff1a;引用 DOM 元素1. 引用通用 DOM 元素&#xff08;HTMLElement&#xff09;2. 引用特定类型的 DOM 元素&#xff08;如 HTMLDivElement&#xff09; 三、<script setup> 语法中的类型定义四…

Axure形状类组件图标库(共8套)

点击下载《月下倚楼图标库(形状组件)》 原型效果&#xff1a;https://axhub.im/ax9/02043f78e1b4386f/#g1 摘要 本图标库集锦精心汇集了8套专为Axure设计的形状类图标资源&#xff0c;旨在为产品经理、UI/UX设计师以及开发人员提供丰富多样的设计素材&#xff0c;提升原型设计…

01串(二进制串)与集合之间存在天然的对应关系 ← bitset

【集合的二进制表示‌】 ● 01 串&#xff08;二进制串&#xff09;与集合之间存在天然的对应关系。对应机理为每个二进制位可以表示集合中一个元素的存在&#xff08;1&#xff09;或不存在&#xff08;0&#xff09;。例如&#xff0c;集合 {a, b, c} 的子集 {a, c} 可以表示…

vba学习系列(10)--外观报表

系列文章目录 文章目录 系列文章目录前言一、外观报表1.产能统计2.单板数3.固定伤排查4.件号良率5.镜片批退率6.镜筒批退率 总结 前言 一、外观报表 1.产能统计 Sub ProcessInspectionData()Dim ws1 As Worksheet, ws2 As Worksheet, ws3 As WorksheetDim lastRow1 As Long, …

machine_env_loader must have been assigned before creating ssh child instance

在主机上执行roslaunch命令时&#xff0c;报错&#xff1a;machine_env_loader must have been assigned before creating ssh child instance。 解决办法&#xff1a; 打开hostos文件&#xff0c;检查local host 前的内部ip是否正常。操作示例&#xff1a; 先输入下方指令打…

CSS radial-gradient函数详解

目录 基本语法 关键参数详解 1. 渐变形状&#xff08;Shape&#xff09; 2. 渐变大小&#xff08;Size&#xff09; 3. 中心点位置&#xff08;Position&#xff09; 4. 颜色断点&#xff08;Color Stops&#xff09; 常见应用场景 1. 基本圆形渐变 2. 椭圆渐变 3. 模…

分析Web3下数据保护的创新模式

在这个信息爆炸的时代&#xff0c;我们正站在 Web3 的门槛上&#xff0c;迎接一个以去中心化、用户主权和数据隐私为核心的新时代。Web3 不仅仅是技术的迭代&#xff0c;它更是一场关于数据权利和责任的结构性变革。本文将探讨 Web3 下数据保护的创新模式&#xff0c;以期为用户…

RabbitMQ-Go 性能分析

更多个人笔记见&#xff1a; &#xff08;注意点击“继续”&#xff0c;而不是“发现新项目”&#xff09; github个人笔记仓库 https://github.com/ZHLOVEYY/IT_note gitee 个人笔记仓库 https://gitee.com/harryhack/it_note 个人学习&#xff0c;学习过程中还会不断补充&…

AI助力Java开发:减少70%重复编码,实战效能提升解析

工具再先进&#xff0c;也替代不了编程思维的深度锤炼 在Java开发领域&#xff0c;重复编码如同无形的生产力黑洞——以商品管理模块开发为例&#xff0c;开发者耗费大量时间编写SQL查询、处理结果集转换&#xff1b;用户系统里&#xff0c;密码加密和状态管理的代码在不同项目…

JS语法笔记

目录 JS数组Array新建数组一维数组二维数组 reverse()在数组末尾插入&#xff1a;push()在数组末尾删除&#xff1a;pop()在数组开头插入&#xff1a;unshift()从数组开头删除一个元素shift()splice() MapSet JS数组Array 判断数组相等不能用&#xff0c;要循环判断 新建数组…

uniapp-商城-77-shop(8.2-商品列表,地址信息添加,级联选择器picker)

地址信息,在我们支付订单上有这样一个接口,就是物流方式,一个自提,我们就显示商家地址。一个是外送,就是用户自己填写的地址。 这里先说说用户的地址添加。需要使用到的一些方式方法,主要有关于地址选择器,就是uni-data-picker级联选择。 该文介绍了电商应用中地址信息处…

网页前端开发(基础进阶3--Vue)

Vue3 Vue是一款用于构建用户界面的渐进式的JavaScript框架。 Vue由2部分组成&#xff1a;Vue核心包&#xff0c;Vue插件包 Vue核心包包含&#xff1a;声明式渲染&#xff0c;组件系统。 Vue插件包&#xff1a;VueRouter&#xff08;客户端路由&#xff09;&#xff0c;Vuex…

大模型相关技术综述

多模态大模型&大模型训练语料持续迭代 已经开始整理多模态-视觉部分&#xff1a; 主要分为一下几块 多模态信息压缩模型&#xff08;clip、vit、swiT&#xff09; 生成模型&#xff08;vae、gan、flow、ddpm、sde…) 其它多模态大模型&#xff08;语音、视频、slam、3…

Vue3中Ant-design-vue的使用-附完整代码

前言 首先介绍一下什么是Ant-design-vue Ant Design Vue 是基于 Vue 3 的企业级 UI 组件库&#xff08;同时兼容 Vue 2&#xff09;&#xff0c;是蚂蚁金服开源项目 Ant Design 的 Vue 实现版本。它遵循 Ant Design 的设计规范&#xff0c;提供丰富的组件和高质量的设计体系&…

建造者模式:优雅构建复杂对象

引言 在软件开发中&#xff0c;有时我们需要创建一个由多个部分组成的复杂对象&#xff0c;这些部分可能有不同的变体或配置。如果直接在一个构造函数中设置所有参数&#xff0c;代码会变得难以阅读和维护。当对象构建过程复杂&#xff0c;且需要多个步骤时&#xff0c;我们可…