• C++11中for循环新用法容易产生的误区


    对于std::list,最基本的遍历方式可能是这样的:

    list<int> l = { 0,1,2,3,4 };
    for (list<int>::iterator it = l.begin(); it != l.end(); i++) {
        cout << *it << endl;
    }

    std::list的iterator内部维护着指向内部节点的指针,begin和end函数返回对应节点的iterator。

    iterator begin() noexcept
    {    // return iterator for beginning of mutable sequence
        return (iterator(this->_Myhead()->_Next, _STD addressof(this->_Get_data())));
    }

    iterator实现了对应节点的++、--,*等运算符,维护这个for循环。

    _List_const_iterator operator--(int)
    {    // postdecrement
        _List_const_iterator _Tmp = *this;
        --*this;
        return (_Tmp);
    }
    _List_const_iterator operator++(int)
    {    // postincrement
        _List_const_iterator _Tmp = *this;
        ++*this;
        return (_Tmp);
    }
    _NODISCARD reference operator*() const
    {    // return designated value
        return (this->_Ptr->_Myval);
    }

    所以说在这个循环过程中,我们得到的迭代器其实是维护了一个指针的中间层对象,并不是内部节点对象。

    而我们使用使用c++11的范围循环就不一样了,c++11的范围循环有以下两种用法:

    for (auto &it : la) {  //按引用循环
        it.add();
    }
    for (auto it : la) {  //按值循环
        cout << it.get() << endl;  
    }

    按值循环的方式与std::list迭代器所提供的遍历方式大相径庭,会将list的内部节点拷贝到循环变量it中,也就是说使用按值循环的方式修改的只是个临时变量,并没有修改list的内部节点:

    int main()
    {
        list<int> l = { 0,1 };
    
        for (auto it : l) {  //正确的写法:for (auto &it : l) {
            it++;
        }
        for (auto it : l) {  //在遍历时还会调用拷贝构造函数,增加开销
            cout << it << endl;
        }
    
        getc(stdin);
        return 0;
    }
    //Output: 
    //0
    //1

    这种范围的原理和algorithm中提供的for_each()类似:

    template<class InputIterator, class Function>
      Function for_each(InputIterator first, InputIterator last, Function fn)
    {
      while (first!=last) {
        fn (*first); 
        ++first;
      }
      return fn;      // or, since C++11: return move(fn);
    }

    for_each将内部节点的指针解引用,以右值的形式传递,如果我们不将function的参数类型变为引用,就无法修改内部节点。

    int main()
    {
        list<int> l = { 0,1 };
    
        for_each(l.begin(), l.end(), [](int x) -> void{    
            x++;
        });
        for (auto it : l) { cout << it << endl; }    // 0 1
        for_each(l.begin(), l.end(), [](int &x) -> void {
            x++;
        });
        for (auto it : l) { cout << it << endl; }    // 1 2
    
        getc(stdin);
        return 0;
    }
  • 相关阅读:
    Python变量小秘密
    Python编解码问题与文本文件处理
    Java持久层框架Mybatis入门
    teprunner重磅更新Git打通PyCharm与测试平台
    JMeter定时器设置延迟与同步
    Docker开启安全的TLS远程连接
    消息队列之如何保证消息的幂等性
    消息队列之如何保证消息的可靠传输
    spring技术内幕学习笔记01
    linux操作指南-04
  • 原文地址:https://www.cnblogs.com/HadesBlog/p/12774601.html
Copyright © 2020-2023  润新知