迭代器
昨天忽然想到,emplace_back和push_back,emplace_back本质就是移动语义吗,然后在容器后边直接构造,只有一次构造,我就想,那push_back一个右值的时候,是不是和emplace_back一模一样的啊,然后翻了翻以前自己的博客(请神上身了属于是),然后直接绷不住了,写的什么玩意,一点不深刻。有一种看自己五年前QQ动态的美(人果然不能共情曾经的自己)。
实际上哈,push_back左值右值是不一样的,会调用重载的不同版本的push_back函数,都要调用构造函数创建对象,区别只在于传入左值调用拷贝构造函数,传入右值调用移动构造函数,而emplace_back是完美转发参数给内部,调用的构造函数。
到此为止。
———————————————————不知道华不华丽的分割线—————————————————
迭代器,用b站宇文新粥的说法,就是给指针穿上了华丽的衣服,是指针的钢铁侠战甲
迭代器,实际上是类or结构体,里面封装了一个对应容器的指针,以及所有相关的操作符重载,目的就是让迭代器有指针的所有功能
为什么要迭代器而不是指针
因为容器是多种多样的,比如vector是内存分布在相邻地址,而list就是链表,每个节点相隔甚远,map什么的用红黑树实现就更别说了,而容器算法很多又是通用的,比如sort(list不能用),find等,为了让list也能用类似原生指针的东西访问,我们采用了迭代器。
不同容器的迭代器是不一样的,比如vector就很类似原生指针,而其他的只是重载函数实现了类似效果
容器与迭代器的关系
- 每个容器类(如
std::vector,std::list,std::map等)都在其内部定义了至少一种或多种迭代器类型(例如iterator和const_iterator)。这些迭代器类型是该容器的友元类,或者直接定义在容器类内部,以便访问容器的私有成员(如vector的底层数组指针,list的节点指针)。 - 容器的
begin()和end()成员函数负责创建并返回该容器特定类型的迭代器对象。
迭代器特性 (Iterator Traits)
标准库算法(如 std::sort, std::find)是泛型的,它们通过模板参数接收迭代器。为了知道传入的迭代器具备哪些能力(属于哪个类别),以及它指向的元素类型是什么,标准库使用了一个叫做 std::iterator_traits 的模板元编程技术。
std::iterator_traits<Iterator> 可以提取出迭代器的以下信息:
iterator_category: 迭代器类别(如std::random_access_iterator_tag)value_type: 迭代器指向的元素类型difference_type: 两个迭代器之间的距离类型pointer: 指向元素类型的指针类型reference: 元素类型的引用类型
自定义的迭代器需要通过继承 std::iterator 或在迭代器类中定义这些 typedef 来配合 std::iterator_traits。
type traits(类型萃取)
主要体现在算法如何根据迭代器的特性来选择最优化的实现路径。
核心机制是通过 std::iterator_traits 这个类型萃取模板来实现的。
1. std::iterator_traits 的作用
std::iterator_traits 是一个特殊的类型萃取模板,它的作用是从任何迭代器类型 Iterator 中提取出关于该迭代器的标准信息。这些信息通常是通过迭代器类内部定义的 typedef 来提供的。std::iterator_traits 会查找并暴露这些嵌套类型,使得算法可以通过统一的方式访问它们。
std::iterator_traits<Iterator> 通常会提供以下几个重要的嵌套类型(即萃取出的特性):
value_type: 迭代器所指向元素的类型。difference_type: 用于表示两个迭代器之间距离的类型(通常是ptrdiff_t)。pointer: 迭代器指向元素的指针类型。reference: 迭代器指向元素的引用类型。iterator_category: 这是一个非常重要的特性,它指示了迭代器的能力(例如,输入迭代器、前向迭代器、随机访问迭代器等)。
std::iterator_traits 还为原始指针类型(如 T*)提供了偏特化,使得原始指针也能像 STL 迭代器一样工作,并被识别为随机访问迭代器。
2. 迭代器分类与标签 (Iterator Categories and Tags)
iterator_category 是连接 Type Traits 和迭代器能力的关键。C++ 定义了一系列的标签类型来表示不同的迭代器类别,它们之间存在继承关系:
std::input_iterator_tag(输入迭代器)std::output_iterator_tag(输出迭代器)std::forward_iterator_tag(前向迭代器) - 继承自input_iterator_tag和output_iterator_tagstd::bidirectional_iterator_tag(双向迭代器) - 继承自forward_iterator_tagstd::random_access_iterator_tag(随机访问迭代器) - 继承自bidirectional_iterator_tag
一个迭代器类型通过在其内部定义 iterator_category 为这些标签类型之一,来声明自己的能力。例如,std::vector 的迭代器内部会定义 typedef std::random_access_iterator_tag iterator_category;。
3. 算法如何利用 std::iterator_traits 和分类标签
STL 算法(如 std::advance, std::distance, std::copy, std::sort 等)是模板函数,它们接受迭代器作为参数。在算法的内部实现中,它们会使用 std::iterator_traits 来获取迭代器的特性,尤其是 iterator_category。
基于 iterator_category 的不同,算法会采用不同的实现策略。这通常通过标签分派 (Tag Dispatching) 或 C++17 后的 if constexpr 来实现,这是一种编译时多态。




