美文网首页
C++ iterator遍历 你会用吗?

C++ iterator遍历 你会用吗?

作者: starmier | 来源:发表于2019-11-01 17:29 被阅读0次

先来问初始化一个容器

        std::map<uint32_t, std::string> namelist;
    auto ret_pr = namelist.insert(std::make_pair(1, "1111"));
    namelist.insert(ret_pr.first, std::make_pair (2, "2222"));
    namelist[3] = "3333";

下面我们通过两种方式来遍历这个容器,如下所示:

//方法一:
        for (std::map<uint32_t, std::string>::iterator iter = namelist.begin(); iter != namelist.end(); iter++)
    {
        uint32_t num = iter->first;
        std::string name = iter->second;
        printf("--0--num :%d, name:%s.\n",num,name.c_str());
    }
    
//方法二:  
    for (std::map<uint32_t, std::string>::iterator iter = namelist.begin(); iter != namelist.end(); ++iter)
    {
        uint32_t num = iter->first;
        std::string name = iter->second;
        printf("--0--num :%d, name:%s.\n",num,name.c_str());
    }

没有什么不同,我们看下执行结果

--0--num :1, name:1111.
--0--num :2, name:2222.
--0--num :3, name:3333.
--0--num :1, name:1111.
--0--num :2, name:2222.
--0--num :3, name:3333.

回答正确,两种方式都完美的遍历了所有的元素,那下面我们来看看每次每一轮迭代器的值吧

for (std::map<uint32_t, std::string>::iterator iter = namelist.begin(); iter != namelist.end(); )//iter++
    {
        uint32_t num = iter->first;
        std::string name = iter->second;
        
        printf("--0--num :%d, name:%s.\n",num,name.c_str());
        
        printf("--0--num :%d.\n",(iter++)->first);
        
    }
    
    printf("\n-----------------------------------\n");
    for (std::map<uint32_t, std::string>::iterator iter = namelist.begin(); iter != namelist.end(); )//++iter
    {
        uint32_t num = iter->first;
        std::string name = iter->second;
        
        printf("--0--num :%d, name:%s.\n",num,name.c_str());
        
        printf("--0--num :%d.\n",(++iter)->first);
    }

再来看下运行结果:

--0--num :1, name:1111.
--0--num :1.
--0--num :2, name:2222.
--0--num :2.
--0--num :3, name:3333.
--0--num :3.

-----------------------------------
--0--num :1, name:1111.
--0--num :2.
--0--num :2, name:2222.
--0--num :3.
--0--num :3, name:3333.
--0--num :803247488.

大家看出来区别来吗?方法一是 后置递增,方法二是后置递增,这个会带来什么影响呢?功能上是没有影响的,但是性能上会有些差别。

后者内部需要一个临时对象,因为他必须存放迭代器的原本位置并返回之

_Myiter& operator++()                                //前置++重载
        {   // preincrement
        ++*(_Mybase *)this;
        return (*this);
        }
 
    _Myiter operator++(int)                    //有int参数 后置++重载
        {   // postincrement
        _Myiter _Tmp = *this;
        ++*this;
        return (_Tmp);
        }

后置式递增特点,在很多类运算符重载中,都需要为后置++和--在函数中定义一个临时变量,用于保存被更改之前变量的值作为返回值,然后在函数体中队变量进行相应操作。
Object a,b;

b=a++; 直观上来看,在a++中进行赋值操作前不能把a值改变, a的值赋前已经改变,只是b接受的是a改变前的副本temp当作的返回值

而前置式为先做自增自减运算,所以只需要对本身进行操作然后返回。由于后置式多出了这一步,所以效率低。

我们简单写个代码来验证下

       std::map<uint32_t, std::string> namelist;
        for (int i = 0; i<1000000; i++)
    {
        namelist.insert(std::make_pair(i, std::to_string(i)));
    }

        uint32_t startTime = getTime();
    printf("\n------------------%d-----------------\n", startTime);
    
    for (std::map<uint32_t, std::string>::iterator iter = namelist.begin(); iter != namelist.end();iter++ )
    {
        uint32_t num = iter->first;
        std::string name = iter->second;
        
    }
    
    uint32_t endTime = getTime();
    printf("\n------------------%d(diff:%d)-----------------\n", endTime, endTime-startTime);
    for (std::map<uint32_t, std::string>::iterator iter = namelist.begin(); iter != namelist.end(); ++iter)
    {
        uint32_t num = iter->first;
        std::string name = iter->second;
    }
    uint32_t endTime1 = getTime();
    printf("\n------------------%d(diff:%d)-----------------\n", endTime1, endTime1-endTime);

我们来看下结果, 明显看出但就简单的遍历来讲, 使用前置式递增preincrement的优点,它比后置式递增postincrement效率高

------------------643006724-----------------

------------------643006976(diff:252)-----------------

------------------643007212(diff:236)-----------------

相关文章

网友评论

      本文标题:C++ iterator遍历 你会用吗?

      本文链接:https://www.haomeiwen.com/subject/hkcqbctx.html