前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >四种流迭代器之间的转换关系

四种流迭代器之间的转换关系

作者头像
用户9831583
发布2022-12-04 16:26:25
5350
发布2022-12-04 16:26:25
举报
文章被收录于专栏:码出名企路码出名企路

迭代器

//迭代器:iterator, const_iterator, reverse_iterator , const_reverse_iterator //流迭代器:istreambuf_iterator和 istream_iterator //它们之间的关系是什么?可以互相转化吗?可以混合使用吗?

条款23:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator

/** 解释以下迭代器:container 1, iterator的作用相当于 T,而const_iterator则相当于const T:从容器的开头向尾部的遍历中让你移动到容器的下一个元素 2,reverse_iterator同样相当于T,const_reverse_iterator相当于const T,从尾部向头部移到容器的下一个元素 我有足够的理由让你选择 iterator */

//理由一:inset和erase的实现 //有些标准容器包含了如下函数,只接受iterator类型

代码语言:javascript
复制
iterator insert(iterator position, const T& x);
iterator erase(iterator position);
iterator erase(iterator rangeBegin,iterator rangeEnd);

//貌似验证后不是这样的!!!见 1

//http://c.biancheng.net/view/7196.html

代码语言:javascript
复制
    //1
    set<int> v = { 1, 2, 3 };
    set<int>::const_iterator i;
    for (i = v.begin(); i != v.end(); ++i) {
        if (i == v.begin()) {
            i = v.insert(i, 5);
            i = v.erase(i);
        }
    }

//理由二:几种迭代器之间的转换关系

//iterattor到const_iterator, iterator到reverse和从 reverse_iterator到const_reverse_iterator可以进行隐式转换 //reverse_iterator可以通过base成员函数转换为iterator, const_reverse_iterator也可以类似通过base转换成为const_iterator //但是, 发现 const_iterator无法转换成iterator

//理由三:iterator和const_iterator之间的比较

代码语言:javascript
复制
typedef deque<int> IntDeque;

typedef IntDeque::iterator Iter;

typedef IntDeque::const_iterator ConstIter;

//iterator在比较之前隐式转换成const_iterator , 见2

代码语言:javascript
复制
    //2
    deque<int> d = {1,2,3};
    Iter ii = d.begin();
    ConstIter ci = d.begin();
    if (ii == ci){
        std::cout<<"yes, =="<<std::endl;
    }
    //注意,以上大多数可以用,但是要避免实现将 const_iteratror的operator==作为const_iterator的一个成员函数而不是非成员函数
    //交互位置可以解决,混合使用时候注意,安全映射,将 iterator转换成 const_iterator
    if(static_cast<ConstIter>(ii) - ci == 0){
         std::cout<<"yes, =="<<std::endl;
    }

条款24:用distance和advance把const_iterator转换成iterator

//不能从 const_itertor转换到iterator 证明见 3

代码语言:javascript
复制
    //3
    Iter iii(ci);//错误,没有从const_iterator到iterato的隐式转换
    Iter iii(const_cast<Iter>(ci));//同上
    //原因是两者是完全不同的类,对于 list、set、multiset、map、multimap, deque一样的结果

//如何实现转换呢?见 4

代码语言:javascript
复制
    //4
    //让ci指向d
    Iter i_(d.begin());//初始化i为d.begin()
    ConstIter ci_(d.begin() + 1);
     advance(i_,distance(i_,ci_));//把i移到指向ci的位置
    //理想状态:distance返回两个指向同一个容器的iterator之间的距离;advance则用于将一个iterator移动指定的距离。
    //如果i和ci指向同一个容器,那么表达式advance(i, distance(i, ci))会将i移动到与ci相同的位置上
    //无法通过编译,但是!

//为什么呢?看下distance的定义,见 4-1

代码语言:javascript
复制
//4-1
template<typename InputIterator>
typename iterator_traits<InputIterator>::difference_type
distance(InputIterator first,InputIterator last);
//编译器会根据使用的实参类型推断出 InputIterator的类型,因此以上例子接受两个不同的类型,调用会失败
//需要显式指明distance调用的模板参数类型, 见 4-2
代码语言:javascript
复制
//4-2
     advance(i_,distance<ConstIter>(i_,ci_));

条款25:如何通过 reverse_iterator的base得到iterator

//调用reverse_iterator的base成员函数可以产生“对应的”iterator,但这句话有些辞不达意 //见 5

代码语言:javascript
复制
    //5
    vector<int> v1;
    v1.reserve(5);
    for(int i=0; i<5; i++){
        v1.push_back(i);
    }

    //使用 ri指向 3
    vector<int>::reverse_iterator ri = std::find(v1.rbegin(), v1.rend(),3);
    //使 i和 ri的base一样
    vector<int>::iterator i1(ri.base());
    //https://www.coder.work/article/1236550

    std::cout<<"ri "<<*ri<<" "<<*i1<<std::endl;

//可以看出两者打印的值不同见 图 1

//图1 //可以看出 reverse_iterator和它对应的 base iterator之间特有的偏移量,就像 rbegin()和rend()与相关的begin()和end()一样

//一些函数只允许iterator不允许reverse_iterator,该怎么实现呢?

//假设你在ri指出的位置上把一个新元素插入 v = 99

//ri遍历从右向左,并且插入操作会将新元素插入到 ri位置,将原先ri位置的元素移到编译过程中的下一个位置,因此, 3应该出现在99的左侧

代码语言:javascript
复制
//v1.insert(ri,99); //不能用reverse_iterator

v1.insert(i1,99);

/** 结论: 我们不能用ri来指定插入的地方,因为它不是一个iterator。我们必须用i来代替。如上所述,当ri指向3 时,i(就是ri.base())指向4。如果我们用ri来指定插入位置,那么用i指向插入位置,那个假设就是正确的。 要实现在一个reverse_iterator ri指出的位置上插入新元素,在ri.base()指向的位置插入就行了。对于 insert操作而言,ri和ri.base()是等价的,而且ri.base()真的是ri对应的iterator */

//再来考虑一下删除函数,最初图如下

//如果你要删除ri指向的元素,不能直击用ri,因为 i和ri不是指向的同一个元素,因此,你要删除的是i的前一个元素

代码语言:javascript
复制
 // v1.erase(--ri.base());//尝试删除 ri.base()前面的元素
     //不好 因为 ri.base()的结果是一个指针
    //不能修改函数返回的指针,换一种思考

    //不能减少调用base的返回值,就增加reverse_iterator的值,然后再调用base
   //  v1.erase((++ri).base());

// reverse_iterator的base成员函数返回一个“对应的”iterator的说法并不准确。对于插入操 // 作而言,的确如此;但是对于删除操作,并非如此。当需要把reverse_iterator转换成iterator的时候,有一点非 // 常重要的是你必须知道你准备怎么处理返回的iterator,因为只有这样你才能决定你得到的iterator是否是你需 // 要的。

条款26:避免istream_iterator造成忽略空格后的字符

//https://zhuanlan.zhihu.com/p/76960794

代码语言:javascript
复制
int main()
{
    ifstream in_file("data.txt");
    ofstream out_file("output_file.txt");
    if(!in_file)
    {
        cout<<"filesopen failed!\n";
        return -1;
    }
    istream_iterator<string> is(in_file);  // 自动按照空格分隔
    istream_iterator<string> eof;
    vector<string> text;

    copy(is,eof,back_inserter(text));
    sort(text.begin(),text.end());

     std::cout<<"............."<<text.size()<<std::endl;

    ostream_iterator<string> os(out_file," ");
    copy(text.begin(),text.end(),os);
    return 0;
}

改进之后:

代码语言:javascript
复制
#include <locale>

struct csv_reader: std::ctype<char> {
    csv_reader(): std::ctype<char>(get_table()) {}
    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> rc(table_size, std::ctype_base::mask());

        rc[','] = std::ctype_base::space;
        rc['\n'] = std::ctype_base::space;
        rc[' '] = std::ctype_base::space;
        return &rc[0];
    }
};

int main()
{
    ifstream in_file("data.txt");
    in_file.imbue(locale(locale(), new csv_reader()));
    //下同上
}

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码出名企路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 迭代器
    • 条款23:尽量用iterator代替const_iterator,reverse_iterator和const_reverse_iterator
      • 条款24:用distance和advance把const_iterator转换成iterator
        • 条款25:如何通过 reverse_iterator的base得到iterator
          • 条款26:避免istream_iterator造成忽略空格后的字符
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档