容器迭代器iterator

文章目录

      • 1、自定义String实现iterator
      • 2、自定义vector实现iterator
      • 3、迭代器失效问题

迭代器的功能:提供一种统一的方式,来透明的遍历容器。

迭代器可以透明的访问容器内部的元素的值,而无需了解其底层遍历机制具体是数组的下标还是链表的指针等等。

泛型算法参数接收的都是迭代器!
泛型算法 - 全局的函数 - 给所有容器用的
泛型算法,有一套方式,能够统一的遍历所有的容器的元素 - 迭代器

1、自定义String实现iterator

#include <iostream>
#pragma warning(disable:4996)using namespace std;class String {
public:String(const char *p = nullptr) {if (p != nullptr) {_pstr = new char[strlen(p) + 1];strcpy(_pstr, p);}else {_pstr = new char[1];_pstr[0] = '\0';}}~String() {delete[] _pstr;_pstr = nullptr;}String(const String &str) {_pstr = new char[strlen(str._pstr) + 1];strcpy(_pstr, str._pstr);}String &operator=(const String &str) {if (this == &str) return *this;delete[] _pstr;_pstr = new char[strlen(str._pstr) + 1];strcpy(_pstr, str._pstr);return *this;}bool operator>(const String &str) const {return strcmp(_pstr, str._pstr) > 0;}bool operator<(const String &str) const {return strcmp(_pstr, str._pstr) < 0;}bool operator==(const String &str) const {return strcmp(_pstr, str._pstr) == 0;}int length() const { return strlen(_pstr); }const char *c_str() const { return _pstr; }//char ch=str6[6]; str6[6]='7'char &operator[](int index) { return _pstr[index]; }//char ch=str6[6]; 不允许修改! str6[6]='7'const char &operator[](int index) const { return _pstr[index]; }// 给string字符串类型提供迭代器的实现class iterator {public:iterator(char *p = nullptr) : _p(p){}bool operator!=(const iterator &it) {return _p != it._p;}void operator++() {++_p;}char &operator*() {return *_p;}private:char *_p;};// begin返回的是容器底层首元素的迭代器的表示iterator begin() { return iterator(_pstr); }// end返回的是容器末尾元素后继位置的迭代器的表示iterator end() { return iterator(_pstr + length()); }private:char *_pstr;friend String operator+(const String &lhs, const String &rhs);friend ostream &operator<<(ostream &out, const String &str);
};String operator+(const String &lhs, const String &rhs) {//char *ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];//strcpy(ptmp, lhs._pstr);//strcat(ptmp, rhs._pstr);//return String(ptmp); // 内存泄漏:ptmp 未释放//char *ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];//strcpy(ptmp, lhs._pstr);//strcat(ptmp, rhs._pstr);//String tmp(ptmp); // 效率太低//delete[] ptmp; //return tmp;String result;delete[] result._pstr; // 释放默认构造的空字符串内存result._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];strcpy(result._pstr, lhs._pstr);strcat(result._pstr, rhs._pstr);return result;
}ostream &operator<<(ostream &out, const String &str) {out << str._pstr;return out;
}int main() {String str1 = "hello world!";// 容器的迭代器类型String::iterator it = str1.begin();for (; it != str1.end(); ++it) {cout << *it << " ";}cout << endl;// C++11 foreach的方式来遍历容器的内部元素的值 => 底层,还是通过迭代器进行for (auto s : str1) {cout << s << " ";}cout << endl;return 0;
}

2、自定义vector实现iterator

#include <iostream>
using namespace std;template<typename T>
class vector {
public:vector(int size = 10) {_first = new T[size];_last = _first;_end = _first + size;}~vector() {delete[]_first;_first = _last = _end = nullptr;}vector(const vector<T> &rhs) {int size = rhs._end - rhs - _first;_first = new T[size];int len = rhs._last - rhs._first;for (int i = 0; i < len; ++i) {_first[i] = rhs._first[i];}_last = _first + len;_end = _first + size;}vector<T> &operator=(const vector<T> &rhs) {if (this == &rhs) {return *this;}delete[]_first;int size = rhs._end - rhs - _first;_first = new T[size];int len = rhs._last - rhs._first;for (int i = 0; i < len; ++i) {_first[i] = rhs._first[i];}_last = _first + len;_end = _first + size;return *this;}void push_back(const T &val) {if (full()) {expand();}*_last++ = val;}void pop_back() {if (empty()) {return;}--_last;}T back() {// 返回容器末尾元素的值return *(_last - 1);}bool full() const { return _last == _end; }bool empty() const { return _last == _first; }int size() const { return _end - _first; }T &operator[](int index) { // vec[2]if (index < 0 || index >= size()) {throw "OutOfRangeException";}return _first[index];}//迭代器一般实现成容器的嵌套类型class iterator {public:iterator(T *ptr = nullptr) : _ptr(ptr){}bool operator!=(const iterator &it) const {return _ptr != it._ptr;}void operator++() {_ptr++;}T &operator*() {return *_ptr;}private:T *_ptr;};// 需要给容器提供begin和end方法iterator begin() { return iterator(_first); }iterator end() { return iterator(_last); }private:T *_first; // 指向数组空间的起始位置T *_last;// 指向数组中有效元素的后继位置T *_end;// 指向数组空间的后继位置void expand() {int size = _end - _first;T *ptmp = new T[size * 2];for (int i = 0; i < size; ++i) {ptmp[i] = _first[i];}delete[] _first;_first = ptmp;_last = _first + size;_end = _last + size;}
};class Test {
public:Test() { cout << "Test()" << endl; }~Test() { cout << "~Test()" << endl; }
};int main() {vector<int> vec;for (int i = 0; i < 20; ++i) {vec.push_back(rand() % 100);}for (int i = 0; i < vec.size();  ++i) {cout << vec[i] << " ";}cout << endl;//vector<int>::iterator it = vec.begin();auto it = vec.begin();for (; it != vec.end(); ++it) {cout << *it << " ";}cout << endl;for (auto v : vec) {cout << v << " ";}cout << endl;return 0;
}

3、迭代器失效问题

问题引入

	vector<int> vec;for (int i = 0; i < 20; ++i) {vec.push_back(rand() % 100);}// 把vec容器中所有的偶数全部删除auto it = vec.begin();for (; it != vec.end(); ++it) {if (*it % 2 == 0) {//迭代器失效的问题,第一次调用erase以后,迭代器it就失效了vec.erase(it);  // insert(it,val) erase(it)break;}}//给vec容器中所有的偶数前面添加一个小于偶数值1的数字auto it= vec.begin();for (; it != vec.end(); ++it) {if (*it % 2 == 0) {// 这里的迭代器在第一次insert之后,iterator就失效了vec.insert(it, *it - 1);break;}}	

迭代器为什么会失效?

a. 当容器调用erase方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。

b. 当容器调用insert方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。
    首元素-> 插入点/删除点:迭代器依然有效
    插入点/删除点->末尾元素:迭代器全部失效

c. insert来说,如果引起容器内存扩容。
    首元素-> 插入点/删除点 ->末尾元素:原来容器的所有的迭代器就全部失效了

迭代器失效了以后,问题该怎么解决?

对插入/删除点的迭代器进行更新操作。

	vector<int> vec;for (int i = 0; i < 20; ++i) {vec.push_back(rand() % 100);}for (auto v : vec) {cout << v << " ";}cout << endl;// 把vec容器中所有的偶数全部删除auto it = vec.begin();while (it != vec.end()) {if (*it % 2 == 0) {//迭代器失效的问题,第一次调用erase以后,迭代器it就失效了it = vec.erase(it);  // insert(it,val) erase(it)}else {++it;}}for (auto v : vec) {cout << v << " ";}cout << endl;//给vec容器中所有的偶数前面添加一个小于偶数值1的数字auto it = vec.begin();for (; it != vec.end(); ++it) {if (*it % 2 == 0) {// 这里的迭代器在第-次insert之后,iterator就失效了it = vec.insert(it, *it - 1);//break;++it;}}	for (auto v : vec) {cout << v << " ";}cout << endl;

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

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

相关文章

对象的实例化、内存布局与访问定位

一、创建对象的方式 二、创建对象的步骤: 一、判断对象对应的类是否加载、链接、初始化: 虚拟机遇到一条new指令&#xff0c;首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已经被加载、解析和初始化…

传输层协议 UDP 与 TCP

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; 前置复盘&#x1f98b; 传输层&#x1f98b; 再谈端口号&#x1f98b; 端口号范围划分&#x1f98b; 认识知名端口号 (Well-Know Port Number) 二&#xf…

实验十一 Servlet(二)

实验十一 Servlet(二) 【实验目的】 1&#xff0e;了解Servlet运行原理 2&#xff0e;掌握Servlet实现方式 【实验内容】 改造实验10&#xff0c;引入数据库&#xff0c;创建用户表&#xff0c;包括用户名和密码&#xff1a;客户端通过login.jsp发出登录请求&#xff0c;请求…

服务SDK三方新版中央仓库和私服发布详解

预备信息Github仓库发布Gradle版本匹配Gradle项目构建全局变量定义Gradle项目Nexus仓库配置与发布过程Gradle项目发布至Sonatype中央仓库配置过程总结当我们在实现一个项目技术总结、工具类封装或SDK封装,通常是为了方便开发者使用特定服务或平台而提供的一组工具和API。您可能…

git 新项目

新项目git 新建的项目如何进行git 配置git git config --global user.name "cc" git config --global user.email ccexample.com配置远程仓库路径 // 添加 git remote add origin http://gogs/cc/mc.git //如果配错了&#xff0c;删除 git remote remove origin初…

openmv的端口被拆分为两个 导致电脑无法访问openmv文件系统解决办法 openmv USB功能改动 openmv驱动被更改如何修复

我之前误打误撞遇到一次&#xff0c;直接把openmv的全部端口删除卸载然后重新插上就会自动重新装上一个openmv端口修复成功&#xff0c;大家可以先试试不行再用下面的方法 全部卸载再重新插拔openmv 要解决OpenMV IDE中出现的两个端口问题&#xff0c;可以尝试以下步骤&#x…

利用Python高效处理大规模词汇数据

在本篇博客中&#xff0c;我们将探讨如何使用Python及其强大的库来处理和分析大规模的词汇数据。我们将介绍如何从多个.pkl文件中读取数据&#xff0c;并应用一系列算法来筛选和扩展一个核心词汇列表。这个过程涉及到使用Pandas、Polars以及tqdm等库来实现高效的数据处理。 引…

LabVIEW双光子成像系统:自主创新,精准成像,赋能科研

双光子成像系统&#xff1a;自主创新&#xff0c;精准成像&#xff0c;赋能科研 第一部分&#xff1a;概述 双光子成像利用两个低能量光子同时激发荧光分子&#xff0c;具有深层穿透、高分辨率、低光损伤等优势。它能实现活体深层组织的成像&#xff0c;支持实时动态观察&…

Deepseek-R1 和 OpenAI o1 这样的推理模型普遍存在“思考不足”的问题

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Vue3学习笔记-Vue开发前准备-1

一、安装15.0或更高版本的Node.js node -v npm -v 二、创建Vue项目 npm init vuelatest 三、Vue项目结构 node_modules: Vue项目运行的依赖文件public&#xff1a;资源文件夹package.json&#xff1a;信息描述文件

Denavit-Hartenberg DH MDH坐标系

Denavit-Hartenberg坐标系及其规则详解 6轴协作机器人的MDH模型详细图_6轴mdh-CSDN博客 N轴机械臂的MDH正向建模&#xff0c;及python算法_mdh建模-CSDN博客 运动学3-----正向运动学 | 鱼香ROS 机器人学&#xff1a;MDH建模 - 哆啦美 - 博客园 机械臂学习——标准DH法和改进MDH…

自然语言生成(NLG)算法模型评估方案的硬件配置、系统架构设计、软件技术栈、实现流程和关键代码

智能化对话中的自然语言生成&#xff08;NLG&#xff09;算法模型评估是一个复杂而多维的过程&#xff0c;它涉及多个评估指标和策略&#xff0c;以确保生成的文本质量、准确性和流畅性。 智能化对话中的NLG算法模型评估是一个涉及多个评估指标和策略的过程。通过选择合适的评估…

排序算法--基数排序

核心思想是按位排序&#xff08;低位到高位&#xff09;。适用于定长的整数或字符串&#xff0c;如例如&#xff1a;手机号、身份证号排序。按数据的每一位从低位到高位&#xff08;或相反&#xff09;依次排序&#xff0c;每次排序使用稳定的算法&#xff08;如计数排序&#…

数据结构:时间复杂度

文章目录 为什么需要时间复杂度分析&#xff1f;一、大O表示法&#xff1a;复杂度的语言1.1 什么是大O&#xff1f;1.2 常见复杂度速查表 二、实战分析&#xff1a;解剖C语言代码2.1 循环结构的三重境界单层循环&#xff1a;线性时间双重循环&#xff1a;平方时间动态边界循环&…

S4 HANA明确税金汇差科目(OBYY)

本文主要介绍在S4 HANA OP中明确税金汇差科目(OBYY)相关设置。具体请参照如下内容&#xff1a; 1. 明确税金汇差科目(OBYY) 以上配置点定义了在外币挂账时&#xff0c;当凭证抬头汇率和税金行项目汇率不一致时&#xff0c;造成的差异金额进入哪个科目。此类情况只发生在FB60/F…

hypermesh中用tcl脚本生成多个线段

hypermesh中原本有利用多个节点生成线段的功能&#xff0c;但实际应用中不太好用&#xff0c;因为hypermesh会自动对线段进行拟合。如果手动生成多个线段&#xff0c;又太繁琐&#xff0c;这里写了一段脚本来自动生成&#xff08;#为注释符号&#xff09;。 set alist {} for …

87.(3)攻防世界 web simple_php

之前做过&#xff0c;回顾 12&#xff0c;攻防世界simple_php-CSDN博客 进入靶场 <?php // 显示当前 PHP 文件的源代码&#xff0c;方便调试或查看代码结构 // __FILE__ 是 PHP 的一个魔术常量&#xff0c;代表当前文件的完整路径和文件名 show_source(__FILE__);// 包含…

pycharm 中的 Mark Directory As 的作用是什么?

文章目录 Mark Directory As 的作用PYTHONPATH 是什么PYTHONPATH 作用注意事项 Mark Directory As 的作用 可以查看官网&#xff1a;https://www.jetbrains.com/help/pycharm/project-structure-dialog.html#-9p9rve_3 我们这里以 Mark Directory As Sources 为例进行介绍。 这…

一个类有一个全局变量 m,多线程对它进行增加操作,如何保证线程安全?

一个类有一个全局变量 m&#xff0c;多线程对它进行增加操作&#xff0c;如何保证线程安全&#xff1f; 在多线程环境下对共享变量进行修改时&#xff0c;确保线程安全的关键是保证操作的原子性、可见性和有序性。以下是针对全局变量 m 的多线程自增操作的线程安全解决方案&am…

CSS关系选择器详解

CSS关系选择器详解 学习前提什么是关系选择器&#xff1f;后代选择器&#xff08;Descendant Combinator&#xff09;语法示例注意事项 子代选择器&#xff08;Child Combinator&#xff09;语法示例注意事项 邻接兄弟选择器&#xff08;Adjacent Sibling Combinator&#xff0…