【STL源码剖析读书笔记】【第3章】迭代器概念与traits编程技法

2023-10-18 05:48

本文主要是介绍【STL源码剖析读书笔记】【第3章】迭代器概念与traits编程技法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、迭代器模式:提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该聚合物的内部表达式。

2、STL的中心思想:将数据容器和算法分开,彼此独立设计,最后用迭代器将它们撮合在一起。

3、迭代器是一种智能指针,最终要的编程工作就是对operator*operator->进行重载工作。

4、迭代器例子

#include<iostream>
#include<algorithm>
using namespace std;template<typename T>
struct ListItem{  //链表节点数据结构ListItem() :m_next(nullptr){}//默认构造函数ListItem(T value, ListItem* p = nullptr) { m_value = value; m_next = p; } //构造函数ListItem* Next() const { return m_next; }  //返回m_next指针T Value() const { return m_value; } //返回值T m_value;  //存储的数据ListItem* m_next; //指向下一个ListItem的指针
};template<typename T>
class List{ //链表数据结构
public:List() :m_begin(nullptr), m_befend(nullptr), m_end(nullptr){} //默认构造函数void Push_back(T value){  //从链表尾部插入元素ListItem<T>* temp = new ListItem<T>(value, nullptr);if (m_begin == nullptr){m_begin = m_befend = temp;}else{m_befend->m_next = temp;m_befend = temp;}}void Push_front(T value){  //从链表头部插入元素ListItem<T>* temp = new ListItem<T>(value);if (m_begin == nullptr){m_begin = m_befend = temp;}else{temp->m_next = m_begin;m_begin = temp;}}ListItem<T>* Begin() const { return m_begin; }  //返回链表头部指针ListItem<T>* End() const { return m_end; }      //返回链表尾部指针void Print(ostream& os = cout) const{        //打印链表元素for (ListItem<T>* p = Begin(); p != End(); p = p->Next())os << p->Value() << " ";os << endl;}
private:ListItem<T>* m_begin; //指向List头部的指针ListItem<T>* m_befend; //指向List最后一个元素的指针ListItem<T>* m_end; //指向List尾部的指针long m_size; //List的长度
};
// ListIter继承STL提供的iterator,保证符合STL所需之规范
template<typename T>
class ListIter :public iterator<forward_iterator_tag, T>{
public:ListIter(T* p = nullptr) :m_ptr(p){}   //默认构造函数T& operator*() const { return *m_ptr; }; //dereference,解引用T* operator->() const { return m_ptr; } //member access,成员访问ListIter& operator++(){ m_ptr = m_ptr->Next(); return *this; } //前置++操作,暴露了ListItem的Next()ListIter operator++(int){ ListIter temp = *this; ++*this; return temp; }//后置++操作bool operator==(const ListIter& i)const{ return m_ptr == i.m_ptr; }//判断两个ListIter是否指向相同的地址bool operator!=(const ListIter& i)const{ return m_ptr != i.m_ptr; }//判断两个ListIter是否指向不同的地址
private:T* m_ptr;  //保持与容器之间的一个联系
};template<typename T>  //本例中value的型别是int,iter的型别是ListItem<int>,必须写operator==重载函数
bool operator==(const ListItem<T>& item, const T& n){return item.Value() == n;
}//template<typename T>  //STL源码剖析中说是要写operator!=重载函数,但是我这边不成功,需要写的是operator==重载函数
//bool operator!=(const ListItem<T>& item, const T& n){
//	return item.Value() != n;
//}int main(){List<int> mylist;for (int i = 0; i < 5; ++i){mylist.Push_front(i);mylist.Push_back(i + 2);}mylist.Print();ListIter<ListItem<int>> begin(mylist.Begin()); //暴露了ListItemListIter<ListItem<int>> end(mylist.End()); //暴露了ListItemListIter<ListItem<int>> iter;iter = find(begin, end, 1);//从链表中查找3if (iter == end)cout << "not found" << endl;elsecout << "found" << endl;     //输出founditer = find(begin, end, 7);//从链表中查找3if (iter == end)cout << "not found" << endl;  //输出not foundelsecout << "found" << endl;system("pause");return 0;
}

上面的例子在main函数中暴露了ListItem,在ListItem暴露了ListItem的Next()。如果不是为了迭代器,ListItem应该完全隐藏起来。所以把迭代器的开发工作交给List的设计者,这样实现细节得以封装不被使用者看到,这也是每一种STL容器有专属迭代器的原因。

5、 迭代器分为五类:

Input Iterator:这种迭代器所指的对象,不允许外界改变。只读(read only)

Output Iterator:只写(write only)

Forward Iterator:在此种迭代器所形成的区间上进行读写操作。

Bidirectional Iterator:可双向移动。

RandomAccess Iterator :前四种迭代器都只供应一部分指针算术能力(前三种支持operator++,第四种再加上operator--),第五种则涵盖所有指针算术能力,包换p+np-np[n]p1-p2p1<p2

6、“特性萃取机”traits:榨取各个迭代器的特性

template<class I>
struct iterator_traits{typedef typename I::value_type  value_type;
};

这个所谓的traits的意义是如果I定义有自己的valuetype,那么通过这个traits的作用,萃取出来的value type就是I::value type。

template<class I>
struct iterator_traits<I*>{typedef I value_type; //偏特化版——迭代器是原生指针
};
template<class I>
struct iterator_traits<const I*>{typedef I value_type; //偏特化版——迭代器是pointer-to-const时,萃取出来的型别是I而非const I
};

template<class I>
struct iterator_traits{typedef typename I::iterator_category  iterator_category;typedef typename I::value_type  value_type;typedef typename I::difference_type difference_type;typedef typename I::pointer pointer;typedef typename I::reference reference;
};
7、   迭代器相应型别:

1)  valuetypevalue type是指迭代器所指对象的类型。

2)  difference typedifference type用来表示两个迭代器之间的距离。

3)  reference typereference type是指迭代器所指对象的类型的引用。

4)  pointer type: pointer type是指迭代器所指对象的指针。

5)  iterator_categoryiterator_category是指迭代器的类型。共有5种迭代器类型。

//五个作为标记用的型别

struct input_iterator_tag{};
struct output_iterator_tag{};
struct forward_iterator_tag:public input_iterator_tag{};
struct bidirectional_iterator_tag :forward_iterator_tag{};
struct random_access_iterator_tag : public bidirectional_iteratir_tag{};
8、 STL 提供了一个iterator类,每个新设计的迭代器都继承自它,这样就能保证这些自定义的迭代器符合STL所需的规范,iterator类具体定义如下:

template<typename Category,typename T,typename Distance = ptrdiff_t,typename Pointer = T*,typename Reference = T&>
struct iterator
{typedef Category iterator_category;typedef T value_type;typedef Distance difference_type;typedef Pointer pointer;typedef Reference reference;
};
traits 编程技法大量运用于 STL 实现中,它利用 内嵌类型 的编程技巧与编译器的参数推导功能,增强 C++ 未能提供的关于型别认证方面的能力。

这篇关于【STL源码剖析读书笔记】【第3章】迭代器概念与traits编程技法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/230575

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念