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

c++STL-通用(反向)迭代器适配器

c++STL-通用(反向)迭代器适配器

  • 反向迭代器原理
  • 易错情况:临时对象的常属性
  • 库里的反向迭代器
  • 反向迭代器需要支持的功能
  • 通用反向迭代器适配器模板参考程序

反向迭代器原理

建议先看c++STL-string的使用-CSDN博客、c++STL-list的使用和迭代器-CSDN博客。

可以用正向迭代器适配出反向迭代器。

//三个模板参数分别是
//迭代器,有效数据的引用,有效数据的地址类型
template<class Iterator, class Ref, class Ptr>
class reverse_iterator{//...
};

Iterator是其他容器的正向迭代器,但没说是哪一个的。

反向迭代器需要用正向迭代器来构造。

之后反向迭代器的++,通过调用正向迭代器的--来实现。反向迭代器的--,也通过调用正向迭代器的++实现。

reverse_iterator<Iterator, Ref, Ptr>& operator++() {--it;return *this;
}

rbegin()rend()来表示反向迭代器。但它们其实是上传原迭代器通过反向迭代器类进行封装:

typedef T* iterator;
typedef const T* const_iterator;typedef reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;reverse_iterator rbegin(){return reverse_iterator(end() - 1);
}reverse_iterator rend(){return reverse_iterator(begin() - 1);
}const_reverse_iterator rbegin() const{return const_reverse_iterator(end() - 1);
}const_reverse_iterator rend() const{return const_reverse_iterator(begin() - 1);
}

反向迭代器的operator*是调用正向迭代器的*,因此返回值的类型需要通过模板参数来确定。

这种实现方式的类也可以叫迭代器适配器,即反向迭代器底层用正向迭代器来适配。

适配的前提:很多功能是重叠的才能去适配。例如stacklistvectordeque的功能重叠,因此可以适配。

这个反向迭代器理论上也能适配listvectordeque以及其他支持正向迭代器的容器。

易错情况:临时对象的常属性

这里假设vector的迭代器依旧用指针代替,list的迭代器通过类模板实现。

因为临时对象的常属性,因此在生成反向迭代器对象时,常量不能--,编译器报错说只能对左值操作。
请添加图片描述

临时对象具有常属性,但这里--end()的含义不同,按理来说无论是内置类型还是自定义类型,这里生成的临时对象都具有常属性,按理来说都不能--end(),但只有内置类型迭代器的vector报错了,另一个自定义类型迭代器的list没有。

解决方法是用end()-1作为形参上传给反向迭代器。这样临时拷贝不会修改原迭代器的返回值。

此外,匿名对象也具有常属性:

class A{void print(){cout<<"A::print()\n";}
};A& r=A();//不允许
A& r=A(1);//不允许const A& r = A(1);//允许
r.print();//具有常属性的对象可以调用非const修饰的函数,案例来说应该不可以

再比如:

--10;//不允许
10-1;//允许

使用类似end()-1的操作都是为了拿到这个位置。

请添加图片描述

因此上传end()-1,一样能拿到这个位置的值,用这个值再去调用反向迭代器的构造函数生成反向迭代器。

库里的反向迭代器

请添加图片描述

库里采用了对称的设计,反向迭代器的rbegin就是rend

按照之前的设计,这样的迭代器会少枚举元素。

但库里的*it访问的是前一个位置:

reference operator(*) const{Iterator tmp=current;return *--tmp;
}

请添加图片描述

例如通过rbegin访问4,先--自身再访问。

后续的模拟实现主要参考库里的实现。也不能说之前的分析没用,而是学习时可以大胆猜想,再去看看自己想的和大佬的差距在哪里。

反向迭代器需要支持的功能

总结起来就这几个功能:

  1. ++,表示正向迭代器的--
  2. --,表示正向迭代器的++
  3. operator*,表示解引用。访问迭代器指向的数据的前一个位置。
  4. operator->,表示解引用。
  5. !=,表示迭代器的不等于。
  6. ==,表示迭代器的等于。
  7. 需要使用反向迭代器的容器,类的内部加上这几句代码(T是正向迭代器指向的数据的数据类型):
typedef reverse_iterator<iterator, T&, T*> reverse_iterator;
typedef reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;//反向迭代器
reverse_iterator rbegin() {return reverse_iterator(end());
}reverse_iterator rend() {return reverse_iterator(begin());
}const_reverse_iterator rbegin() const {return const_reverse_iterator(end());
}const_reverse_iterator rend() const {return const_reverse_iterator(begin());
}

这里什么也没有做,而是复用了原容器的正向迭代器,用正向迭代器来模拟反向迭代器的功能。

通用反向迭代器适配器模板参考程序

反向迭代器通用模板类:

//三个模板参数分别是
//迭代器,有效数据的引用,有效数据的地址类型
template<class Iterator, class Ref, class Ptr>
class reverse_iterator {
public:typedef reverse_iterator<Iterator, Ref, Ptr> self;reverse_iterator<Iterator, Ref, Ptr>(Iterator _it):it(_it) {}self& operator++() {--it;return *this;}self& operator--() {++it;return *this;}self operator++(int) {Iterator tmp = it--;return self(tmp);}self operator--(int) {Iterator tmp = it++;return self(tmp);}//参考库里的反向迭代器,访问前一个位置Ref operator*() {Iterator tmp = it;return *(--tmp);}//获得数据的地址Ptr operator->() {return &(operator*());}bool operator==(const self& x) const {return it == x.it;}bool operator!=(const self& x) const {return it != x.it;}private:Iterator it;
};

只要容器类增加反向迭代器的接口作为成员函数,并重载有++--*->==!=即可使用。

测试用的命名空间mystd.h

#pragma once
#include<cassert>
#include<queue>
#include<iostream>
using std::ostream;
using std::istream;namespace mystd {template<class T>void swap(T& a, T& b) {T tmp = a;a = b;b = tmp;}//反向迭代器类模板//三个模板参数分别是//迭代器,有效数据的引用,有效数据的地址类型template<class Iterator, class Ref, class Ptr>class reverse_iterator {public:typedef reverse_iterator<Iterator, Ref, Ptr> self;reverse_iterator<Iterator, Ref, Ptr>(Iterator _it):it(_it) {}self& operator++() {--it;return *this;}self& operator--() {++it;return *this;}self operator++(int) {Iterator tmp = it--;return self(tmp);}self operator--(int) {Iterator tmp = it++;return self(tmp);}//参考库里的反向迭代器,访问前一个位置Ref operator*() {Iterator tmp = it;return *(--tmp);}//获得数据的地址Ptr operator->() {return &(operator*());}bool operator==(const self& x) const {return it == x.it;}bool operator!=(const self& x) const {return it != x.it;}private:Iterator it;};class string {public:const static size_t npos;//构造函数string(const char* s = "") {//求s的长度size_t len = 0;const char* tmps = s;while (*tmps) {++len;++tmps;}//初始化长度、容量等信息_size = len;_capacity = len;_str = new char[_capacity + 1]{ '\0' };//拷贝tmps = s;char* tmps2 = _str;while (*tmps2++ = *tmps++);}//析构函数~string() {delete[] _str;_str = nullptr;_size = _capacity = 0;}//返回c风格字符串的地址const char* c_str() const {return _str;}//用[]进行索引访问char& operator[](size_t pos) {assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const {assert(pos < _size);return _str[pos];}//返回当前字符串的长度size_t size()const {return _size;}//返回容量size_t capacity()const {return _capacity;}//迭代器typedef char* iterator;typedef const char* const_iterator;//模板参数的类型要对齐,//例如const_iterator要对应const_reverse_iterator,//则模板参数的迭代器要上传const_iteratortypedef mystd::reverse_iterator<iterator, char&, char*> reverse_iterator;typedef mystd::reverse_iterator<const_iterator, const char&, const char*> const_reverse_iterator;iterator begin() {return _str;}iterator end() {return _str + _size;}const_iterator begin() const {return _str;}const_iterator end() const {return _str + _size;}//反向迭代器reverse_iterator rbegin() {return reverse_iterator(end());}reverse_iterator rend() {return reverse_iterator(begin());}const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}const_reverse_iterator rend() const {return const_reverse_iterator(begin());}//交换,独立于namespace std中的swapvoid swap(string& a) {//两个对象:*this,amystd::swap(_str, a._str);mystd::swap(_size, a._size);mystd::swap(_capacity, a._capacity);}//拷贝构造函数string(const string& str):_str(nullptr)//临时对象不经过构造函数会产生随机数, _size(0), _capacity(0) {string tmp(str._str);//生成第2个临时对象mystd::string::swap(tmp);}//赋值重载:string& operator=(string tmp) {mystd::string::swap(tmp);return *this;}string& operator=(char c) {char ch[2] = { c,'\0' };string tmp(ch);mystd::string::swap(tmp);return *this;}//扩容void reserve(size_t n = 0) {if (n > _capacity) {char* tmp = new char[n + 1]{ '\0' };char* aa = tmp, * bb = _str;while (*aa++ = *bb++);delete[]_str;_str = tmp;_capacity = n;}}void resize(size_t n, char ch = '\0') {if (n <= _size) {_str[n] = '\0';_size = n;while (n < _capacity)_str[n++] = '\0';return;}reserve(n);while (_size < n) {_str[_size] = ch;++_size;}}//插入string& insert(size_t pos, const string& s) {assert(pos <= _size);reserve(_size + s._size);size_t end = _size - 1;while (end >= pos && end != -1) {_str[end + s._size] = _str[end];--end;}for (size_t i = 0; i < s._size; i++) {_str[pos + i] = s[i];}_size += s._size;return *this;}//尾插string& operator+=(const string& s) {insert(_size, s);_str[_size] = '\0';return *this;}string& operator+=(char s) {push_back(s);return *this;}void push_back(char c) {char ch[2] = { c,'\0' };insert(_size, ch);}//比较运算符重载bool operator==(const string& s) const {if (_size != s._size)return 0;for (size_t i = 0; i < s._size; i++) {if (_str[i] != s._str[i]) {return 0;}}return 1;}bool operator<(const string& s) const {for (size_t i = 0; i < s._size && i < _size; i++) {if (_str[i] > s._str[i]) {return 0;}}if (_size > s._size)return 0;return 1;}bool operator>(const string& s) const {return !(*this == s || *this < s);}bool operator>=(const string& s) const {return !(*this < s);}bool operator<=(const string& s) const {return !(*this > s);}bool operator!=(const string& s) const {return !(*this == s);}//删除string& erase(size_t pos = 0, size_t len = npos) {assert(pos < _size);if (len == npos || pos + len >= _size) {_str[pos] = '\0';_size = pos;return *this;}while (pos + len < _size) {_str[pos] = _str[pos + len];++pos;}_str[pos] = '\0';_size -= len;return *this;}//清空void clear() {_str[0] = '\0';_size = 0;}//查找size_t find(const string& s, size_t pos = 0)const {for (size_t i = 0, ti; i <= _size - s._size; i++) {ti = i;for (size_t j = 0; j < s._size; j++) {if (s[j] == _str[ti])++ti;elsebreak;}if (ti == i + s._size)return i;}return npos;}size_t find(char c, size_t pos = 0)const {for (size_t i = 0; i < _size; i++) {if (_str[i] == c)return i;}return npos;}//提取片段string substr(size_t pos = 0, size_t len = npos)const {string tmp;if (len == npos || pos + len > _size) {while (tmp += _str[pos++], pos < _size);return tmp;}while (tmp += _str[pos++], tmp._size < len);return tmp;}private:char* _str;size_t _size;size_t _capacity;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& st) {for (const auto& x : st)out << x;return out;}istream& operator>>(istream& in, string& s) {s.clear();char buff[129];size_t i = 0;char ch;//连同空格一起接收while (ch = in.get(), ch != ' ' && ch != '\n') {buff[i++] = ch;if (i == 128) {buff[i] = '\0';s += buff;i = 0;}}if (i != 0) {buff[i] = '\0';s += buff;}return in;}template<class T>class vector {public://构造函数vector<T>():_start(nullptr), _finish(nullptr), _endofstorage(nullptr){}vector<T>(size_t n, const T& val = T()): _start(nullptr), _finish(nullptr), _endofstorage(nullptr) {reserve(n);_finish = _start + n;for (size_t i = 0; i < n; i++) {_start[i] = val;}}//析构函数~vector<T>() {delete[]_start;_start = _finish = _endofstorage = nullptr;}//获取容量信息size_t capacity() const {return _endofstorage - _start;}//获取数量size_t size() const {return _finish - _start;}//扩容void reserve(size_t n) {while (n > capacity()) {size_t sz = size();size_t new_c = capacity();new_c = new_c == 0 ? n : new_c * 2;T* tmp = new T[new_c]{ T() };if (_start != nullptr) {for (size_t i = 0; i < sz; i++) {tmp[i] = _start[i];}}_start = tmp;_finish = tmp + sz;_endofstorage = tmp + new_c;}}void resize(size_t n, const T& val) {reserve(n);for (size_t i = size(); i < n; i++)_start[i] = val;_finish = _start + n;}//访问T& operator[](size_t pos) {assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}//迭代器typedef T* iterator;typedef const T* const_iterator;typedef mystd::reverse_iterator<iterator, T&, T*> reverse_iterator;typedef mystd::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;iterator begin() {return _start;}iterator end() {return _finish;}const_iterator begin() const {return _start;}const_iterator end() const {return _finish;}//反向迭代器reverse_iterator rbegin() {return reverse_iterator(end());}reverse_iterator rend() {return reverse_iterator(begin());}const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}const_reverse_iterator rend() const {return const_reverse_iterator(begin());}//插入//单个元素iterator insert(iterator pos, const T& val) {assert(pos >= begin());assert(pos <= end());size_t sz = pos - begin();//计算偏移量reserve(size() + 1);pos = begin() + sz;auto End = end();while (End > pos) {*End = *(End - 1);--End;}*End = val;_finish++;return pos;}//尾插void push_back(const T& val) {insert(end(), val);}//删除//删除指定迭代器iterator erase(iterator pos) {assert(pos >= begin());assert(pos < end());auto tmp = pos;while (tmp < _finish) {*tmp = *(tmp + 1);++tmp;}--_finish;return pos;}//删除区域的迭代器//左闭右开iterator erase(iterator Begin, iterator End) {assert(Begin >= begin());assert(End <= end());assert(Begin <= End);size_t sz = size_t(End - Begin);iterator tmp = Begin;while (tmp + sz < end()) {*tmp = *(tmp + sz);++tmp;}_finish = tmp;return Begin;}//尾删void pop_back() {erase(end() - 1);}//拷贝构造vector<T>(const vector<T>& a):_start(nullptr), _finish(nullptr), _endofstorage(nullptr) {reserve(capacity());for (auto& x : a)push_back(x);}//交换void swap(vector<T>& b) {vector<T>& a = *this;mystd::swap(a._start, b._start);mystd::swap(a._finish, b._finish);mystd::swap(a._endofstorage, b._endofstorage);}//赋值重载vector<T>& operator=(vector<T> tmp) {swap(tmp);return *this;}private:iterator _start;iterator _finish;iterator _endofstorage;};template<class T>struct __list_node {//指针域typedef __list_node* pointer;pointer next;pointer view;//数据域T data;__list_node(const T& x = T()):data(x), next(nullptr), view(nullptr) {}};//list专用迭代器类模板//三个模板参数分别为:存储的数据类型//存储的数据的引用、存储的数据空间的地址类型template<class T, class Ref, class Ptr>struct __list_iterator {typedef __list_iterator<T, Ref, Ptr> self;typedef __list_node<T>* link_node;link_node node;__list_iterator<T, Ref, Ptr>(link_node x = nullptr):node(x) {}__list_iterator<T, Ref, Ptr>(const self& x): node(x.node) {}Ref operator*() {return node->data;}//为了支持T为自定义类型的情况//返回迭代器指向的结点的数据域的地址Ptr operator->() {return &node->data;}bool operator==(const self& x) const {return node == x.node;}bool operator!=(const self& x) const {return node != x.node;}self& operator++() {node = node->next;return *this;}self& operator--() {node = node->view;return *this;}self operator++(int) {self tmp(*this);node = node->next;return tmp;}self operator--(int) {self tmp(*this);node = node->view;return tmp;}};template<class T>class list {public:typedef __list_node<T> Node;//默认构造函数list<T>() {node = get_node();node->next = node->view = node;_size = 0;}//构造函数list<T>(int n, const T& val = T()) {node = get_node();node->next = node->view = node;size_t tmp = n;for (size_t i = 0; i < tmp; i++)push_back(val);}list<T>(size_t n, const T& val = T()) {node = get_node();node->next = node->view = node;size_t tmp = n;for (size_t i = 0; i < tmp; i++)push_back(val);}template<class Inputiterator>list<T>(Inputiterator first, Inputiterator second) {node = get_node();node->next = node->view = node;while (first != second) {push_back(*first);first++;}}//拷贝构造函数list<T>(const list<T>& obj) {node = get_node();node->next = node->view = node;for (const auto& x : obj)this->push_back(x);}//赋值重载list<T>& operator=(list<T>obj) {mystd::swap(this->node, obj.node);mystd::swap(this->_size, obj._size);return *this;}//析构函数~list() {clear();delete node;}//迭代器typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;typedef mystd::reverse_iterator<iterator, T&, T*> reverse_iterator;typedef mystd::reverse_iterator<const_iterator, const T&, const T*> const_reverse_iterator;iterator begin() {return iterator(node->next);}iterator end() {return iterator(node);}const_iterator begin() const {return const_iterator(node->next);}const_iterator end() const {return const_iterator(node);}//反向迭代器reverse_iterator rbegin() {return reverse_iterator(end());}reverse_iterator rend() {return reverse_iterator(begin());}const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}const_reverse_iterator rend() const {return const_reverse_iterator(begin());}//结点数size_t size()const {return _size;}//判断是否为空bool empty()const {return this->node->next == this->node&& this->node->view == this->node;}//头插void push_front(const T& val) {insert(begin(), val);}//尾插void push_back(const T& val) {insert(end(), val);}//尾删void pop_back() {erase(--end());}//头删void pop_front() {erase(begin());}//插入iterator insert(iterator pos, const T& val) {Node* cur = pos.node->view;Node* newnode = get_node(val);newnode->next = cur->next;newnode->view = cur;cur->next = newnode;newnode->next->view = newnode;++_size;return iterator(newnode);}//删除iterator erase(iterator pos) {assert(pos != end());Node* del = pos.node, * cur = pos.node->next;del->view->next = del->next;del->next->view = del->view;delete del;--_size;return iterator(cur);}//清空void clear() {auto it = begin();while (it != end()) {it = erase(it);}}//访问T& front() {return node->next->data;}T& back() {return node->view->data;}private:Node* get_node(const T& x = T()) {Node* tmp = new Node(x);tmp->next = tmp->view = nullptr;return tmp;}template<class Type>friend void mystd::swap(Type&, Type&);Node* node;//哨兵卫size_t _size;//结点数};//stack和queue都是容器适配器,即靠适配器和容器组合生成的STL工具,//这里是部分模拟实现。template <class T, class Sequence = deque<T> >class stack {//...//省略若干库中的友元函数public://...//省略若干库中没必要的typedefprotected:Sequence c;public:bool empty() const { return c.empty(); }size_t size() const { return c.size(); }T& top() { return c.back(); }const T& top() const { return c.back(); }void push(const T& x) { c.push_back(x); }void pop() { c.pop_back(); }};template <class T, class Sequence = deque<T> >class queue {//...//省略若干友元函数public://...//省略若干不重要的typedefprotected:Sequence c;public:bool empty() const { return c.empty(); }size_t size() const { return c.size(); }T& front() { return c.front(); }const T& front() const { return c.front(); }T& back() { return c.back(); }const T& back() const { return c.back(); }void push(const T& x) { c.push_back(x); }void pop() { c.pop_front(); }};
}

相关文章:

  • 算法第十七天|654. 最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树
  • 第十六章 常用存储器介绍
  • 手机相册的 “智能分类” 功能
  • 数学复习笔记 7
  • Playwright 安装配置文件详解
  • Spark缓存-cache
  • 数据擦除标准:1-Pass vs. 3-Pass vs. 7-Pass有什么区别,哪个更好?
  • 【MySQL】第三弹——表的CRUD进阶(一)数据库约束
  • 专栏特辑丨悬镜浅谈开源风险治理之SBOM与SCA
  • 鸿蒙Next开发 获取APP缓存大小和清除缓存
  • Open Source Geospatial Content Management System -GeoNode
  • 《100天精通Python——基础篇 2025 第18天:正则表达式入门实战,解锁字符串处理的魔法力量》
  • Leetcode 3547. Maximum Sum of Edge Values in a Graph
  • Excelize 开源基础库发布 2.9.1 版本更新
  • win部署Jenkins 自动化部署发布后端项目
  • 6. 多列布局/用户界面 - 杂志风格文章布局
  • RabbitMQ 核心概念与消息模型深度解析(一)
  • centos中libc.so.6No such file的解决方式
  • 尼康VR镜头防抖模式NORMAL和ACTIVE的区别(私人笔记)
  • 专栏项目框架介绍
  • 当代科技拟召开债券持有人会议 ,对“H20科技2”进行四展
  • 一手实测深夜发布的世界首个设计Agent - Lovart。
  • “无锡景・江南韵”:中国评弹艺术在尼日利亚收获众多粉丝
  • 《淮水竹亭》:一手好牌,为何打成这样
  • 人民空军:网上出现的“运-20向外方运送物资”为不实消息
  • 金科股份重整方案通过,正式进入重整计划执行环节