c++迭代器

本文详细介绍了C++中的迭代器,包括迭代器辅助函数如advance和distance,以及迭代适配器如逆向迭代器和转移迭代器。讨论了next()与prev()的区别,并介绍了iterator_traits库用于获取迭代器属性。同时,文章提到了boost库中的iterator_facade和iterator_adaptor,用于简化自定义迭代器的实现过程。

一: 迭代器辅助函数, 方便的操作迭代器

advance(Iterator, n) : 使迭代器前进或后退n个位置, 直接改动迭代器, 不返回值

distance(Iterator_first,Iterator_last ): 计算两个迭代器的距离

iter_swap(Iterator ,Iterator) 交换两个迭代器所指元素的值, 不是交换两个迭代器

    vector<int> v1;
    v1={1,2,3};

    auto i1=v1.begin();
    auto i2=v1.end();
    auto i3=v1.end();
    assert(  i2==i3  );
    iter_swap(i1,i2);
    assert(  i2==i3  ); //交换后还成立

二: 迭代适配器:把一种迭代器转换为另一种迭代器

标准库里有如下几种

逆向迭代器: 反序迭代

转移迭代器: 迭代器返回右值引用

插入迭代器: 赋值操作转换为插入操作

流迭代器:    把IO流转换为迭代器操作

插入迭代器:

    vector<int> v1,v2;

    //直接创建v1的插入迭代器
    auto it=back_inserter(v1);
    *it=1;//将1加入到v1中。
    *it=2;//将2加入到v1中

    //对v2创建插入迭代器, 把v1的元素全部插入到v2
    copy(v1.begin(),v1.end(), back_inserter(v2));

流迭代器:

//直接创建cout的流迭代器
auto out=ostream_iterator<int>(cout);
*out=1;//将1加入到 out里(即cout<<1)
*out=2;//将1加入到 out里(即cout<<2)

//*out="b";     error ,上面已经指定了流迭代器类型为int

//输出v1的每个元素, 第二个参数可用于控制分隔标志
copy(v1.begin(),v1.end(), ostream_iterator<int>(cout,"\n"));

三:next()与prev()

上面提到advance无返回值, 且会修改原迭代器

而boost库的next()和prior函数,  标准库里的next()和prev()提供可以获取第n个迭代器但不改变原迭代器的功能

boost库的next函数简要, 其中用了模板元编程

template<typename T>
inline T next(T x)
{return ++x;}

template<typename T,typename Distance>
inline T next(T x,Distance n) //这里传形参不传引用
{
    std::advance(x,n);  //不改变实参
    return ++x;
}

而标准库里的next()则使用了默认参数=1

template<class ForwardIterator>
ForwardIterator next(ForwardIterator x, difference_type n = 1);

四:iterator_traits库

iterator_traits库用来获取迭代器(或指针)的属性

可以获取以下五种类型信息

iterator_category        :迭代器的分类
        value_type          :值的类型
        pointer                :指针类型
difference_type           :距离类型
        reference            :引用类型

其中iterator_category即迭代器的分类在标准库里有以下几种

输入迭代器: 只读迭代器,只提供operator++, 可以比较相等

输出迭代器: 只写迭代器,只提供operator++,不能比较

前向迭代器:可以读写, 提供operator++, 可以比较相等赋值

双向迭代器: 在前向迭代器基础上提供operator--

随机访问迭代器: 双向迭代器基础上增加了迭代器的算术运算功能, 提供operator[]operator+=

对应的标签如下, 可以看到继承包含关系

struct input_iterator_tag { }; 

struct output_iterator_tag { };

struct forward_iterator_tag : public input_iterator_tag { };

struct bidirectional_iterator_tag : public forward_iterator_tag { };

struct random_access_iterator_tag : public bidirectional_iterator_tag { };

用iterator_traits对vector<int>的迭代器操作如下

vector<int> v1;
auto it=v1.begin();// 换成int*it;下面断言一样都成立

static_assert(is_same_v<iterator_traits<decltype(it)>::reference            , int &>);
static_assert(is_same_v<iterator_traits<decltype(it)>::iterator_category    , random_access_iterator_tag>);
static_assert(is_same_v<iterator_traits<decltype(it)>::value_type           , int>);
static_assert(is_same_v<iterator_traits<decltype(it)>::pointer              , int*>);
static_assert(is_same_v<iterator_traits<decltype(it)>::difference_type      , long long>);

可知vector<int>迭代器信息如下:

引用类型:         int&

迭代器分类:        random_access_iterator_tag(即随机访问)

值类型:        int

指针类型:        int*

距离类型:        long long

boost库的iterator_traits库和标准库的略有差别, 其中把相应的5个元数据分成5个不同的元函数调用

boost::iterator_category //分类
boost::iterator_pointer   //指针类型
boost::iterator_reference //引用类型
boost::iterator_value    //值类型
boost::iterator_difference //距离类型

五:boost::iterator_facade, 用外观模式提供一个辅助类, 更容易自己创建标准的迭代器

头文件 #include "boost/iterator/iterator_facade.hpp"

核心操作有几个(依据迭代器的类型不必全都实现), 通常声明为private

解引用: dereference(), 实现可读和可写必须

相等比较: equal(), 实现单遍迭代器必须

递增: increment() ,实现可递增迭代器和前向遍历迭代器必须

递减: decrement(), 实现双向遍历迭代器必须

距离计算:advance()和distance_to(), 实现随机访问遍历迭代器必须

iterator_facade有五个模板参数, 对应iterator_traits里的五个迭代器信息

template <
        class Derived                          //迭代器子类
        , class Value                          //值类型
        , class CategoryOrTraversal            //迭代器分类
        , class Reference   = Value&           //引用类型
        , class Difference  = std::ptrdiff_t   //距离类型
>
class iterator_facade;

后面两个可以用缺省参数, 可以只关心前3个

Derived        :子类的名字, 即正在编写的类名称

Value            :迭代器值类型

CategoryOrTraversal: 迭代器分类

boost库对迭代器进行了更细致的分类, 除了标准库的五个外 , 还包括

using iterators::incrementable_traversal_tag;
using iterators::single_pass_traversal_tag;
using iterators::forward_traversal_tag;
using iterators::bidirectional_traversal_tag;
using iterators::random_access_traversal_tag;

用法示例一

#include<bits/stdc++.h>
#include "boost/iterator/iterator_facade.hpp"
using namespace std;

template<typename T>
class vs_iterator :
        public boost::iterator_facade<      //基类链继承技术
                vs_iterator<T>, T,          //子类名和值类型
                boost::single_pass_traversal_tag> //单遍迭代器类型
{
private:
    vector<T> &v;
    int current_pos;
public:
    using super_type = boost::iterator_facade<vs_iterator<T>, T, boost::single_pass_traversal_tag>;
    using this_type = vs_iterator;
    using reference = typename super_type::reference;

    vs_iterator(vector<T> &v_, int pos = 0) : v(v_), current_pos(pos) //构造函数
    {}

    vs_iterator(this_type const &other) : v(other.v), current_pos(other.current_pos) //拷贝构造函数
    {}

    void operator=(this_type const &other)  //赋值函数
    {
        this->v = other.v;
        this->current_pos = other.current_pos;
    }

private:
    friend class boost::iterator_core_access; //必须的友元声明

    reference dereference() const   //解引用操作
    {
        return v[current_pos];
    }

    void increment()            //递增操作
    {
        ++current_pos;
    }

    bool equal(this_type const &other) const //比较操作
    {
        return this->current_pos == other.current_pos;
    }
};

int main()
{
    vector<int> v{1, 2, 3, 4};
    vs_iterator vsi(v);                 //对应v.begin()
    vs_iterator vsi_end(v, v.size());   //对应v.end()

    //使用operator*操作元素
    assert(*vsi == 1);  

    //注意 vsi_end对应v.end(), *vsi_end!=4
    assert(*vsi_end != 4);
    
    //copy算法将元素输出到cout
    copy(vsi, vsi_end, ostream_iterator<int>(cout, ","));
    
    return 0;
}
//输出->
1,2,3,4,

从示例可以看出使用时需要的操作

--  public继承boost::iterator_facade, 且指明模板类型: 子类(当前类), 值类型, 迭代器类型

--  写出接口的实现,这里单边迭代器类型为boost::single_pass_traversal_tag, 需实现

        dereference()
        increment()
        equal

--  必备的友元声明:     friend class boost::iterator_core_access;

示例2: 每次跳跃N步长的迭代器

有漏洞, equal函数貌似无法正确实现

#include<bits/stdc++.h>
#include "boost/iterator/iterator_facade.hpp"

using namespace std;


template<typename T, ptrdiff_t N = 2> //默认步长为2
class step_iterator :
        public boost::iterator_facade<                                             //基类链继承技术
                step_iterator<T>, typename iterator_traits<T>::value_type const,    //子类名和值类型
                boost::single_pass_traversal_tag>                                 //单遍迭代器类型
{
private:
    T iter;
public:
    using super_type = boost::iterator_facade<
            step_iterator<T>, typename boost::iterator_value<T>::type const,
            boost::single_pass_traversal_tag>;
    using this_type = step_iterator;
    using reference = typename super_type::reference;

    step_iterator(T x) : iter(x)
    {}

    step_iterator(this_type const &) = default;

    this_type &operator=(this_type const &) = default;

private:
    friend class boost::iterator_core_access; //必须的友元声明

    reference dereference() const   //解引用操作
    {
        return *iter;
    }

    void increment()            //递增操作
    {
        advance(iter, N);
    }

    bool equal(this_type const &other) const //比较操作
    {
        /*这里疑似有漏洞
         * 直接 return iter == other.iter; 时, 步数大于1时可能跳过比较最后的迭代器,
         * 导致 copy(first, last, ostream_iterator<char>(cout)); 出错
         * 
         * 但用以下的方法又不能正确的比较迭代器是否相等,只是这里copy时没错
         */
        int i;
        for(i=0 ;i <N; i++)
        {
            if(next(iter,i)==other.iter)
                return true;
        }
        return false;
    }
};
int main()
{
    char s[] = "123456789";
    step_iterator<char *> first(s), last(s + sizeof(s)); //改不了步长, step_iterator<char *,3>无效, 还是默认步长2,
    copy(first, last, ostream_iterator<char>(cout));
    return 0;
}

六:iterator_adaptor

派生自iterator_facade, 同样使用了基类链技术, 用法和iterator_facade差不多, 但只需编写少数核心变化的操作函数即可, 用法较简单

有6个模板参数, 通常只用前2个

  template <
      class Derived
    , class Base
    , class Value        = use_default
    , class Traversal    = use_default
    , class Reference    = use_default
    , class Difference   = use_default
  >
  class iterator_adaptor;

被适配对象(Adaptee)必须是可拷贝构造可赋值的, 不一定要有operator++, 也就是说不一定是一个迭代器

用法示例一

#include<bits/stdc++.h>
#include "boost/iterator/iterator_adaptor.hpp"
using namespace std;

template<typename P>
class array_iter:public boost::iterator_adaptor<array_iter<P>,P>
{
    static_assert(  is_pointer_v<P>  );  //保证P是一个指针
public:
    using  super_type = typename array_iter::iterator_adaptor_; //用iterator_adaptor_ 省去了写出一长串模板参数列表声明父类
    array_iter(P x):super_type(x){}         //必要的构造函数
};

int main()
{
    int a[10]={1,2,3};
    array_iter<int*> start(a),finish(a+10);
    start+=1;
    copy(start,finish,ostream_iterator<int>(cout));

    return 0;
}

示例二: 实现访问存储增量数值

每次访问递增迭代器, 就把容器的值加上

值引用类型处须加const, 否则会造成非const引用的问题

大概是这个原因吧?目前不太清楚 

(35条消息) C++非const引用问题:error: cannot bind non-const lvalue reference of type_sampson MrLiang的博客-CSDN博客

#include<bits/stdc++.h>
#include "boost/iterator/iterator_adaptor.hpp"
using namespace std;

template<typename P>
class array_iter : public boost::iterator_adaptor<array_iter<P>, P>
{
    static_assert(is_pointer_v<P>);  //保证P是一个指针
public:
    using super_type = typename array_iter::iterator_adaptor_; //用iterator_adaptor_ 省去了写出一长串模板参数列表声明父类
    array_iter(P x) : super_type(x)
    {}         //必要的构造函数
};

template<typename I>
class delta_iterator : public boost::iterator_adaptor<
        delta_iterator<I>, I,
        typename iterator_traits<I>::value_type,            //值类型
        boost::single_pass_traversal_tag,                  //单向遍历
        typename iterator_traits<I>::value_type const>      //值引用类型, 只读,不加const会报错
{
    friend class boost::iterator_core_access;   //必须的友元声明

    using this_type = delta_iterator;
    using super_type = typename this_type::iterator_adaptor_; //基类定义
    typename super_type::value_type m_value;            //存储当前的值
public:
    delta_iterator(const I &iter) : super_type(iter), m_value(0) //当前值从0开始
    {}

private:
    using super_type::base;
    using super_type::base_reference;

    typename super_type::reference dereference() const
    {
        return m_value + *base();  //返回存储的值+当前的值
    }

    void increment()
    {
        m_value += *base(); //存储的值+=当前的值
        ++base_reference();//迭代器前进
    }

};

int main()
{
    vector<int> a = {1, 2, 3, 4};

    delta_iterator<decltype(a.begin())> start(a.begin()), finish(a.end());

    copy(start, finish, ostream_iterator<int>(cout, ","));

    return 0;
}
//输出->
1,3,6,10

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值