11 vector的实现

注意

实现仿cplus官网的的string类,对部分主要功能实现

实现

文件

#pragma once
#include <string>
#include <assert.h>namespace myvector
{template <class T>class vector{public://iteratortypedef 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;}//constructor//defaultvector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}//fill//匿名对象加const引用生命周期延长至变量结束vector(size_t n, const T& val = T()) :_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){Reserve(n);for (size_t i = 0; i < n; i++){PushBack(val);}}//重载int版,防止调用迭代器区间vector(int n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){Reserve(n);for (int i = 0; i < n; i++){PushBack(val);}}//rangetemplate <class InputIterator>vector(InputIterator first, InputIterator last):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr) //可以使用默认值,不用初始化列表{//迭代器必须用不等于,因为list可能后边的指针更小while (first != last){PushBack(*first);first++;}}//copy 实现深拷贝,不然会浅拷贝vector(const vector<T>& x){//Reserve(x.Capacity());_start = new T[x.Capacity()];//深拷贝,不能用memcpy,避免T是结构仍浅拷贝//memcpy(_start, x._start, sizeof(T) * x.Size());for (size_t i = 0; i < x.Size(); i++){_start[i] = x._start[i];}_finish = _start + x.Size();_end_of_storage = _start + x.Capacity();}//addvoid PushBack(const T& x){if (_finish == _end_of_storage){size_t capacity = Capacity() == 0 ? 4 : Capacity() * 2;Reserve(capacity);}*_finish = x;_finish++;}iterator Insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _end_of_storage){size_t sz = pos - _start;//扩容后的迭代器失效问题,更新posReserve(Capacity() == 0 ? 4 : Capacity() * 2);pos = _start + sz;}iterator end = _finish;while (end > pos){*end = *(end - 1);end--;}*pos = x;_finish++;return pos;}//devoid PopBack(){assert(!Empty());_finish--;}iterator Erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator end = pos;while (end != _finish){*end = *(end + 1);end++;}_finish--;return pos;}//searchT& operator[](size_t pos){assert(pos < Size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < Size());return _start[pos];}//size capacitysize_t Size() const{return _finish - _start;}bool Empty() const{return Size() == 0;}size_t Capacity() const{return _end_of_storage - _start;}void Reserve(size_t n){if (n > Capacity()){T* tmp = new T[n];size_t size = Size();if (_start){//memcpy(tmp, _start, Size() * sizeof(T));for (size_t i = 0; i < Size(); i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + size;_end_of_storage = _start + n;}}//类型()调默认构造,内置类型也可以//首先判断设置的大小是否大于当前size,大于就需要设置参数的数据,同时还考虑扩容void Resize(size_t n, T x = T()){if (n > Size()){if (n > Capacity()){Reserve(n);}while (_finish != _start + n){*_finish = x;_finish++;}}_finish = _start + n;}//destructor~vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}private:iterator _start;iterator _finish;iterator _end_of_storage;};
}

测试

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include "vector.h"using namespace myvector;
//void fun(const vector<int>& x)
//{
//	for (auto ch : x)
//	{
//		std::cout << ch << std::endl;
//	}
//}class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> vv;vv.Resize(numRows, vector<int>());for (size_t i = 0; i < vv.Size(); ++i){vv[i].Resize(i + 1, 0);vv[i][0] = vv[i][vv[i].Size() - 1] = 1;}for (size_t i = 0; i < vv.Size(); ++i){for (size_t j = 0; j < vv[i].Size(); ++j){if (vv[i][j] == 0){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}return vv;}
};//vector<int> fun2()
//{
//	vector<int> s;
//	return s;
//}
int main()
{vector<int> v1;v1.PushBack(1);v1.PushBack(2);v1.PushBack(8);v1.PushBack(3);v1.PushBack(10);v1.PushBack(6);v1.PushBack(1);v1.PushBack(2);v1.PushBack(8);v1.PushBack(3);v1.PushBack(10);v1.PushBack(6);/*std::vector<int> v2;v2.push_back(1);v2.push_back(2);v2.push_back(8);v2.push_back(3);*///v1.PushBack(6);/*vector<int>::iterator pos = std::find(v1.begin(), v1.end(), 2);v1.Insert(pos, 3);*//*vector<int>::iterator pos = v1.begin() + 2;v1.Erase(pos);for (int i = 0; i < v1.Size(); i++){std::cout << v1[i] << " ";}*//*std::vector<int>::iterator pos = v2.begin() + 2;for (int i = 0; i < v2.size(); i++){std::cout << v2[i] << " ";}std::cout << std::endl;*//*fun(v1);*//*v1.PopBack();v1.PopBack();v1.PopBack();*///v1.Resize(8, 4);//vector<int>::iterator pos = std::find(v1.begin(), v1.end(), 5);/*if (pos != v1.end()){pos = v1.Insert(pos, 8);}*///vs insert和erase后迭代器都不能再使用,强制检查//(*pos)++;/*std::vector<int>::iterator it = v2.begin();while (it != v2.end()){if (*it % 2 == 0){it = v2.erase(it);}else{it++;}}*//*std::vector<int>::iterator pos1 = std::find(v2.begin(), v2.end(), 2);v2.erase(pos1);pos1++;*//*vector<int>::iterator it2 = v1.begin();while (it2 != v1.end()){std::cout << *it2 << " ";it2++;}*//*vector<int> v3(10, 5);vector<int>::iterator it2 = v3.begin();while (it2 != v3.end()){std::cout << *it2 << " ";it2++;}*///std::cout << std::endl;//int ary[] = { 5,4,3,2,1 };//vector<int> v4(ary, ary + 3);//排序algorithm头文件的排序//template <class RandomAccessIterator>// sort(RandomAccessIterator first, RandomAccessIterator last);//std::sort(v4.begin(), v4.end());/*vector<int>::iterator it3 = v4.begin();while (it3 != v4.end()){std::cout << *it3 << " ";it3++;}*///降序,要传模板//template <class T> struct greater;/*std::greater<int> g;std::sort(ary, ary + sizeof(ary)/sizeof(ary[0]), g);for (auto ch : ary){std::cout << ch << " ";}*///vector<std::string> v2(3, "111");vector<vector<int>> v3 = Solution().generate(5);for (size_t i = 0; i < v3.Size(); ++i){for (size_t j = 0; j < v3[i].Size(); ++j){std::cout << v3[i][j] << " ";}std::cout << std::endl;}vector<int> v4;v4.Insert(v4.begin(), 4);;return 0;
}

注意事项

vector可以存储任意类型的元素,所以用模板,用三个指针,一个记录数组的首地址,finish记录最后一个元素的下一个地址,end_of_storage记录数组范围的地址,类型是模板T类型指针

vector(size_t n, const T& val = T())

对于T类型的值给默认值,不能默认给0,有可能是自定义结构,所以需要调用对应的构造函数,内置类型也可以这样构造

拷贝构造不能用memcpy,如果对象涉及资源管理就会浅拷贝,内存泄露或崩溃,所以要用赋值走运算符重载
在这里插入图片描述

赋值运算符重载,避免T是结构体的浅拷贝

Insert中元素的长度在扩容前需要记录,不然会失效

迭代器失效

迭代器的作用是让算法不用关心底层数据结构,实际就是一个指针,或者是对指针封装。比如:vector的迭代器就是原生态指针T*。因此迭代器失效,实际就是迭代器对应指针的指向的空间销毁了,使用一块已经被释放的空间,造成的后果就是程序崩溃

1.会引起底层空间改变的操作,都有可能是迭代器失效,如:resize、reserve、insert、assign、pushback等

#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{1,2,3,4,5,6};auto it = v.begin();// 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容// v.resize(100, 8);// reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变// v.reserve(100);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.insert(v.begin(), 0);// v.push_back(8);// 给vector重新赋值,可能会引起底层容量改变v.assign(100, 8);/*出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
空间,而引起代码运行时崩溃。解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
赋值即可。*/while(it != v.end()){cout<< *it << " " ;++it;}cout<<endl;return 0;
}

插入时扩容会导致原pos的迭代器失效,所以要记录长度更新pos

2.指定位置元素的删除操作 erase

#include <iostream>
using namespace std;
#include <vector>
int main()
{int a[] = { 1, 2, 3, 4 };vector<int> v(a, a + sizeof(a) / sizeof(int));// 使用find查找3所在位置的iteratorvector<int>::iterator pos = find(v.begin(), v.end(), 3);// 删除pos位置的数据,导致pos迭代器失效。v.erase(pos);cout << *pos << endl; // 此处会导致非法访问return 0;
}

erase删除pos位置的元素后,pos位置之后的元素会往前移,没有导致底层空间改变,理论上迭代器不会失效,但如果pos刚好是最后一个元素,删完之后就是end的位置,end是没有元素的,pos就失效了。因此删除任意位置元素vs就认为迭代器已经失效,会报错

下面是删除所有偶数的功能,第2个是正确的,通过返回值更新pos,迭代器就不会失效

#include <iostream>
using namespace std;
#include <vector>
int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)v.erase(it);++it;}return 0;
}
int main()
{vector<int> v{ 1, 2, 3, 4 };auto it = v.begin();while (it != v.end()){if (*it % 2 == 0)it = v.erase(it);else++it;}return 0;
}

3.liux下,g++编译器对迭代器的检测不严格,没有vs极端

// 1. 扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{vector<int> v{1,2,3,4,5};for(size_t i = 0; i < v.size(); ++i)cout << v[i] << " ";cout << endl;auto it = v.begin();cout << "扩容之前,vector的容量为: " << v.capacity() << endl;// 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效 v.reserve(100);cout << "扩容之后,vector的容量为: " << v.capacity() << endl;// 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会// 虽然可能运行,但是输出的结果是不对的while(it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
程序输出:
1 2 3 4 5
扩容之前,vector的容量为: 5
扩容之后,vector的容量为: 100
0 2 3 4 5 409 1 2 3 4 5
// 2. erase删除任意位置代码后,linux下迭代器并没有失效
// 因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{vector<int> v{1,2,3,4,5};vector<int>::iterator it = find(v.begin(), v.end(), 3);v.erase(it);cout << *it << endl;while(it != v.end()){cout << *it << " ";++it;}cout << endl;return 0;
}
程序可以正常运行,并打印:
4
4 5// 3: erase删除的迭代器如果是最后一个元素,删除之后it已经超过end
// 此时迭代器是无效的,++it导致程序崩溃
int main()
{vector<int> v{1,2,3,4,5};// vector<int> v{1,2,3,4,5,6};auto it = v.begin();while(it != v.end()){if(*it % 2 == 0)v.erase(it);++it;}for(auto e : v)cout << e << " ";cout << endl;return 0;
}
========================================================
// 使用第一组数据时,程序可以运行
[@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[@VM-0-3-centos 20220114]$ ./a.out
1 3 5
=========================================================
// 使用第二组数据时,程序最终会崩溃
[@VM-0-3-centos 20220114]$ vim testVector.cpp
[@VM-0-3-centos 20220114]$ g++ testVector.cpp -std=c++11
[@VM-0-3-centos 20220114]$ ./a.out
Segmentation fault

从上面是三个例子可以看出:SGI STL迭代器失效并不一定崩溃,但运行结果肯定不对,it不在begin和end范围,肯定会崩溃

4.与vector类似,string插入+扩容+erase之后,迭代器也会失效

#include <string>
void TestString()
{string s("hello");auto it = s.begin();// 放开之后代码会崩溃,因为resize到20会string会进行扩容// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了// 后序打印时,再访问it指向的空间程序就会崩溃//s.resize(20, '!');while (it != s.end()){cout << *it;++it;}cout << endl;it = s.begin();while (it != s.end()){it = s.erase(it);// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后// it位置的迭代器就失效了// s.erase(it); ++it;}
}

迭代器失效,对迭代器重新赋值

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

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

相关文章

【AI绘画】AI绘画免费网站推荐

人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是指一种模拟人类智能的技术。它是通过计算机系统来模拟人的认知、学习和推理能力&#xff0c;以实现类似于人类智能的行为和决策。人工智能技术包含多个方面&#xff0c;包括机器学习、深度学习、自…

第42期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…

【C++11】来感受lambda表达式的魅力~

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

redis题库详解

1 什么是Redis Redis(Remote Dictionary Server) 是一个使用 C 语言编写的&#xff0c;开源的&#xff08;BSD许可&#xff09;高性能非关系型&#xff08;NoSQL&#xff09;的键值对数据库。 Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串&#xff0c;…

《OWASP TOP10漏洞》

0x01 弱口令 产生原因 与个人习惯和安全意识相关&#xff0c;为了避免忘记密码&#xff0c;使用一个非常容易记住 的密码&#xff0c;或者是直接采用系统的默认密码等。 危害 通过弱口令&#xff0c;攻击者可以进入后台修改资料&#xff0c;进入金融系统盗取钱财&#xff0…

ENVI 如何批量拆分多波段栅格

在处理遥感图像时&#xff0c;需要将多波段栅格进行拆分是很常见的需求。下面介绍一种方法&#xff0c;可以实现图像批量拆分并重命名。 打开ENVI的App Store 搜索并下载应用 在ENVI的App Store中搜索"将多波段图像拆分成多个单波段文件"&#xff0c;并下载安装。 打…

OceanBase4.2版本 Docker 体验

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

当电脑加域控后,自动移入指定的OU

在Active Directory&#xff08;AD&#xff09;环境中&#xff0c;要实现当计算机加入域时自动被放置到指定的OU&#xff08;组织单元&#xff09;&#xff0c;通常需要配置组策略对象&#xff08;GPO&#xff09;中的计算机账户默认位置或者使用redircmp命令来重定向新加入域的…

视频AI方案:数据+算力+算法,人工智能的三大基石

背景分析 随着信息技术的迅猛发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐渗透到我们生活的各个领域&#xff0c;从智能家居到自动驾驶&#xff0c;从医疗诊断到金融风控&#xff0c;AI的应用正在改变着我们的生活方式。而数据、算法和算力&#xff0c;正是构…

2024 年 2 月 NFT 行业动态:加密货币飙升,NFT 市场调整

作者&#xff1a;stellafootprint.network 数据来源&#xff1a;NFT 研究页面 - Footprint Analytics 2024 年 2 月&#xff0c;加密货币与 NFT 市场显现出了复杂性。该月&#xff0c;NFT 领域的交易量达到 12 亿美元&#xff0c;环比下降了 3.7%。值得关注的是&#xff0c;包…

【IC验证】数组

一、非组合型数组 1.声明 logic [31:0] array [1024]; 或者logic [31:0] array [1023:0]; 或者logic array [31:0] [1023:0]; 理解成一维数组就表示array 数组中有1024个数据&#xff0c;每个数据32bit。 也可以理解为二维数组。 int [1:0][2:0]a1[3:0][4:0]这是一个4523维…

springboot267大学生科创项目在线管理系统的设计与实现

# 大学生科创项目在线管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装大学生科创项目在…

【论文阅读】ACM MM 2023 PatchBackdoor:不修改模型的深度神经网络后门攻击

文章目录 一.论文信息二.论文内容1.摘要2.引言3.作者贡献4.主要图表5.结论 一.论文信息 论文题目&#xff1a; PatchBackdoor: Backdoor Attack against Deep Neural Networks without Model Modification&#xff08;PatchBackdoor:不修改模型的深度神经网络后门攻击&#xf…

数据结构从入门到精通——树和二叉树

树和二叉树 前言一、树概念及结构1.1树的概念1.2 树的相关概念&#xff08;重要&#xff09;1.3 树的表示1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 二、二叉树概念及结构2.1二叉树概念2.2现实中的二叉树2.3 特殊的二叉树2.4 二叉树的性质2.5 二叉…

基于Java+SpringBoot+vue+element疫情药品采购出入库系统设计实现

基于JavaSpringBootvueelement疫情药品采购出入库系统设计实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留…

(2)(2.12) Robsense SwarmLink

文章目录 前言 1 规格&#xff08;根据制造商提供&#xff09; 2 EasySwarm 3 参数说明 前言 Robsense SwarmLink 遥测无线电可将多架无人机连接到一个地面站&#xff0c;而无需在地面站一侧安装多个无线电&#xff08;即创建一个网状网络&#xff09;。此外&#xff0c;还…

在项目管理中,如何更好地协同团队成员,提高团队合作效率?

在项目管理中&#xff0c;协同团队成员并提高团队合作效率是确保项目成功实施的关键。以下是一些建议&#xff0c;有助于更好地协同团队成员&#xff0c;提高团队合作效率&#xff1a; 一、明确角色与责任 为每个团队成员分配明确的角色和职责&#xff0c;通过制定详细的任务…

用chatgpt写论文重复率高吗?如何降低重复率?

ChatGPT写的论文重复率很低 ChatGPT写作是基于已有的语料库和文献进行训练的&#xff0c;因此在写作过程中会不可避免地引用或借鉴已有的研究成果和观点。同时&#xff0c;由于ChatGPT的表述方式和写作风格与人类存在一定的差异&#xff0c;也可能会导致论文与其他文章相似度高…

程序人生——Java中基本类型使用建议

目录 引出Java中基本类型使用建议建议21&#xff1a;用偶判断&#xff0c;不用奇判断建议22&#xff1a;用整数类型处理货币建议23&#xff1a;不要让类型默默转换建议24&#xff1a;边界、边界、还是边界建议25&#xff1a;不要让四舍五入亏了一方 建议26&#xff1a;提防包装…

掘根宝典之C++迭代器简介

在C中&#xff0c;容器是一种用于存储和管理数据的数据结构。C标准库提供了多种容器&#xff0c;每种容器都有其独特的特点和适用场景。 我们知道啊&#xff0c;我们可以通过下标运算符来对容器内的元素进行访问&#xff0c;但是只有少数几种容器才同时支持下标运算符&#xf…