STL const_iterator转iterator

STL const_iterator转iterator教程

STL 中,我们如果需要将 const_iterator 转换为 iterator 可以借助 advance()distance() 函数。

C++ STL 标准库为了方便用户更轻松地操作容器,每个容器的模板类都提供有丰富且实用的方法。在这些方法中,有些是以 const_iterator 类型迭代器作为参数,也就意味着在使用此类方法时,需要为其传入一个 const_iterator 类型的迭代器。

例如,vector 容器模板类中提供有 insert() 方法,该方法的语法格式如下:

iterator insert (const_iterator position, const value_type& val);

注意,此方法有多种语法格式,这里仅列举了其中的一种。可以看到,如果想调用此格式的 insert() 方法,就需要为其传入一个 const_iterator 类型的迭代器。对于给 const_iterator 类型的迭代器传值,还可以使用 iterator 类型迭代器,但不能使用 const_reverse_iterator 和 reverse_iterator 类型迭代器,这是为什么呢?

实际上,当我们将某一类型的迭代器传递给 insert() 方法中 const_iterator 类型的 position 形参时,即便类型不匹配,编译器也不会立即报错,而是先尝试将其类型转换成 const_iterator 类型,如果转换成功,则程序仍可以正常执行;反之如果转换失败,编译器才会报错。

C++ 中,通常将编译器自行尝试进行类型转换的整个过程称为隐式转换(或者自动类型转换)。对于 C++ STL 标准库中的这 4 种基础迭代器来说,C++ 编译器的隐式转换仅支持以下 2 种情况:

  • 将 iterator 类型的迭代器隐式转换为 const_iterator 类型的迭代器;
  • 将 reverse_iterator 类型的迭代器隐式转换为 const_reverse_iterator 类型的迭代器。

注意,以上 2 种隐式转换是单向的,即编译器只支持从 iterator 转换为 const_iterator,从 reverse_iterator 转换为 const_reverse_iterator,但不支持逆向转换。

有些读者可能会好奇,既然隐式转换无法做到,还有其他方式可以实现从 const_iterator 到 iterator、从 const_reverse_iterator 到 reverse_iterator 的转换吗?

很多读者可能会想到使用强制类型转换(const_cast)的方式。但可以明确的是,强制类型转换并不适用于迭代器,因为 const_cast 的功能仅是去掉某个类型的 const 修饰符,但 const_iterator 和iterator 是完全不同的 2 个类,同样 const_reverse_iterator 和 reverse_iterator 也是完全不同的 2 个类,它们仅仅是类名有 const 的差别,但并不是 const T 和 T 的关系。

这里给读者推荐一种实现方式,就是使用 advance() 和 distance() 这 2 个函数,其语法格式如下:

//将 const_iterator 转换为 iterator advance(iter, distance<cont<T>::const_iterator>(iter,citer)); //将 const_reverse_iterator 转换为 reverse_iterator advance(iter, distance<cont<T>::const_reverse_iterator>(iter,citer));

其中,citer 为指向某个容器(比如 cont)任意位置的 const_iterator(或者 const_reverse_iterator)类型迭代器,而 iter 通常初始为指向 cont 容器中第一个元素的 iterator(或者 reverse_iterator)类型迭代器。通过套用此格式,最终 iter 会变成一个指向和 citer 一样的 iterator(或者 reverse_iterator)类型迭代器。

注意,在使用 distance() 函数时,必须额外指明 2 个参数为 const 迭代器类型,否则会因为传入的 iter 和 citer 类型不一致导致 distance() 函数编译出错。

该实现方式的本质是,先创建一个迭代器 citer,并将其初始化为指向容器中第一个元素的位置。在此基础上,通过计算和目标迭代器 iter 的距离(调用 distance()),将其移动至和 iter 同一个位置(调用 advance()),由此就可以间接得到一个指向同一位置的 iter 迭代器。

比如如下代码:

#include <iostream> #include <vector> using namespace std; int main() { cout << "嗨客网(www.haicoder.net)\n" << endl; vector<int>value{ 1,2,3,4,5 }; vector<int>::const_iterator citer = --value.cend(); vector<int>::iterator iter = value.begin(); advance(iter, distance<vector<int>::const_iterator>(iter, citer)); cout <<"*citer = " << *citer << endl; cout << "*iter = " << *iter << endl; return 0; }

我们在 Linux 下使用 g++ 进行编译,具体命令如下:

g++ reverse_iterator.cpp -std=c++11

编译后,我们直接运行生成的二进制文件 a.out,如下图所示:

17_STL const_iterator转iterator.png

可以看到,通过使用 advance() 和 distance() 函数的组合格式,最终可以得到一个和 citer 指向相同但类型为 iterator 的迭代器。

注意,此方法的实现效率仍取决于目标容器的迭代器类型,如果是随机访问迭代器,则该方法的执行效率为 O(1);反之,则执行效率为 O(n)。

STL const_iterator转iterator总结

在 STL 中,我们如果需要将 const_iterator 转换为 iterator 可以借助 advance() 和 distance() 函数。