C++11 推荐只要可以,尽量用const类型的迭代器

本文探讨了C++中迭代器的最佳使用方式,特别是在C++11及以后版本中使用const迭代器的优点。通过示例代码展示了如何在不同C++标准下正确地使用迭代器进行搜索和插入操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 主要内容

    • 核心内容

      • 迭代时,只要不修改,都建议用const类型的迭代器.

      • C++98的迭代器简单难用,C++11则加强了,希望广泛使用.

    • 好处

      • 减小被修改的风险.

    • 迭代器

      • ++,--这种,各类容器的操作抽象化.
      • 比如数组的迭代器++,--是偏移,链表的则是切换节点,树的++,--则是递归遍历.

      • 其他的容器就更加复杂了.

    • 迭代器的好处

      • 将复杂的操作统一且抽象化了.
      • 隐藏细节,使用简单.

  2. const迭代器

    • 什么时候推荐

      • 迭代的时候,没有修改元素的需求,就建议用const迭代器.
    • C++98

      • const类型的迭代器支持不好,特别是STL容器.

    • C++98缺陷

      • 创建复杂,使用麻烦,功能有限.
    • C++98的需求

      • 从一个std::vector<int>中搜索1983,然后在其后面插入1998.
      • 没有找到则插在末尾.
    • 实现

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      int main() {
         std::vector<int> years {1983};
         auto iter = std::find(years.begin(),years.end(),1983);
         years.insert(iter + 1,1998);
         for(auto i = years.begin(); i != years.end();i++) {
             std::cout << *i << std::endl;
         }
      }
      
      • 很简单.

      • 问题:不修改值却用了非const的迭代器,有被修改的风险.

      • 不能有一丝丝的风险.不能让安全隐患存在.

    • C++11

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      int main() {
         std::vector<int> years {1983};
         typedef std::vector<int>::const_iterator IterType;
         IterType iter = std::find(static_cast<IterType>(years.begin()),
                               static_cast<IterType>(years.end()),
                               1983);
      
         years.insert(static_cast<IterType>(iter),1998);
         for(auto i = years.begin(); i != years.end();i++) {
             std::cout << *i << std::endl;
         }
      }
      
      • 可以正常编译执行.

    • c++98版本

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      int main() {
         std::vector<int> years;
         years.push_back(1983);
         typedef std::vector<int>::const_iterator IterType;
         IterType iter = std::find(static_cast<IterType>(years.begin()),
                               static_cast<IterType>(years.end()),
                               1983);
      
         years.insert(static_cast<IterType>(iter),1998);
         for(auto i = years.begin(); i != years.end();i++) {
             std::cout << *i << std::endl;
         }
      }
      
      • c++98编译报错.

      • g++ test.cpp -std=c++98.

      • typedefc++98版本的别名.

      • 输出

      [root@localhost test]# g++ test.cpp -std=c++98
      test.cpp: In function ‘int main():
      test.cpp:13:50: error: no matching function for call to ‘std::vector<int>::insert(__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, int)’
          years.insert(static_cast<IterType>(iter),1998);
                                                       ^
      test.cpp:13:50: note: candidates are:
      In file included from /usr/include/c++/4.8.2/vector:69:0,
                      from test.cpp:3:
      /usr/include/c++/4.8.2/bits/vector.tcc:107:5: note: std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, const value_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = int*; std::vector<_Tp, _Alloc>::value_type = int]
          vector<_Tp, _Alloc>::
          ^
      /usr/include/c++/4.8.2/bits/vector.tcc:107:5: note:   no known conversion for argument 1 from ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >’ to ‘std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}’
      In file included from /usr/include/c++/4.8.2/vector:64:0,
                      from test.cpp:3:
      /usr/include/c++/4.8.2/bits/stl_vector.h:1023:7: note: void std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp, _Alloc>::size_type, const value_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<int*, std::vector<int> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = int*; std::vector<_Tp, _Alloc>::size_type = long unsigned int; std::vector<_Tp, _Alloc>::value_type = int]
            insert(iterator __position, size_type __n, const value_type& __x)
            ^
      /usr/include/c++/4.8.2/bits/stl_vector.h:1023:7: note:   candidate expects 3 arguments, 2 provided
      /usr/include/c++/4.8.2/bits/stl_vector.h:1050:9: note: template<class _InputIterator> void std::vector<_Tp, _Alloc>::insert(std::vector<_Tp, _Alloc>::iterator, _InputIterator, _InputIterator) [with _InputIterator = _InputIterator; _Tp = int; _Alloc = std::allocator<int>]
              insert(iterator __position, _InputIterator __first,
              ^
      /usr/include/c++/4.8.2/bits/stl_vector.h:1050:9: note:   template argument deduction/substitution failed:
      test.cpp:13:50: note:   cannot convert ‘iter’ (type ‘__gnu_cxx::__normal_iterator<const int*, std::vector<int> >) to type ‘std::vector<int>::iterator {aka __gnu_cxx::__normal_iterator<int*, std::vector<int> >}’
          years.insert(static_cast<IterType>(iter),1998);
                                                       ^
      test.cpp:14:14: error: ‘i’ does not name a type
          for(auto i = years.begin(); i != years.end();i++) {
                   ^
      test.cpp:14:33: error: expected ‘;’ before ‘i’
          for(auto i = years.begin(); i != years.end();i++) {
                                      ^
      test.cpp:14:33: error: ‘i’ was not declared in this scope
      
      
      • 错误信息,insert不能是const类型.

      • 核心是对迭代器的支持不够,c++98则进行了加强.c++14也进行了加强.

      • 所以后面就推荐用迭代器,且const类型的迭代器。

    • 核心观念

      • 推荐用const是因为C++11const进行了加强.

      • c++98对相关支持比较少.

      • 推荐const可以减少错误率.

  3. c++11

    • 改进

      • 获取const迭代器更加容易.

      • 容器有cbegin,cend可以获取const迭代器. 不论是否是const类型容器.

      • STL容器支持用const迭代器进行指定,增删的位置.

      • 即上面的易错版C++98代码简单修改就可以在c++11标准下使用。

    • C++11const版本

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      int main() {
        std::vector<int> years {1983};
        auto iter = std::find(years.cbegin(),years.cend(),1983);
        years.insert(iter + 1,1998);
        for(auto i = years.cbegin(); i != years.cend();i++) {
            std::cout << *i << std::endl;
        }
      }
      
      • 可以正常执行.

  4. 需求

    • 更加通用的函数

      • 抽象成模板函数,如果使用成员的cbegincend就有点问题.毕竟有的没有实现.

      • 没有实现的可以通过特例化实现.

    • 改成通用型

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      template<typename Container,typename T = typename Container::value_type>
      void insert(Container && years,T val) {
         auto iter = std::find(std::cbegin(years),std::cend(years),val);
         years.insert(iter,1998);
         for(auto i = years.cbegin(); i != years.cend();i++) {
             std::cout << *i << std::endl;
         }
      }
      
      int main() {
         std::vector<int> t{1983};
         insert(t,1);
      }
      
      
      • c++14可以编译通过,但是c++11不能.

      • 因为std::cbeginc++14之后补齐的.而且c++11insert不支持const.

      • cbegin, cend, rbegin, rend, crbegin, and crend都是。

    • c++11

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      template<typename T>
      auto my_cbegin(const T& t) 
         -> decltype(std::begin(t)) {
             return std::begin(t);
      }
      template<typename T>
      auto my_cend(const T& t) 
         -> decltype(std::end(t)) {
             return std::end(t);
      }
      
      
      template<typename Container,typename T = typename Container::value_type>
      void insert(Container && years,T val) {
         auto iter = std::find(years.begin(),years.end(),val);
         years.insert(iter,1998);
         for(auto i = my_cbegin(years); i != my_cend(years);i++) {
             std::cout << *i << std::endl;
         }
      }
      
      int main() {
         std::vector<int> t{1983};
         insert(t,1);
      }
      
      
      • 可执行.

    • c++14版本

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      template<typename T>
      auto my_cbegin(const T& t) 
         -> decltype(std::begin(t)) {
             return std::begin(t);
      }
      template<typename T>
      auto my_cend(const T& t) 
         -> decltype(std::end(t)) {
             return std::end(t);
      }
      
      
      template<typename Container,typename T = typename Container::value_type>
      void insert(Container && years,T val) {
         auto iter = std::find(my_cbegin(years),my_cend(years),val);
         years.insert(iter,1998);
         for(auto i = my_cbegin(years); i != my_cend(years);i++) {
             std::cout << *i << std::endl;
         }
      }
      
      int main() {
         std::vector<int> t{1983};
         insert(t,1);
      }
      
      
      • 可行,因为c++14insert支持const和非const.

    • 三方版

      #include <iostream>
      #include <algorithm>
      #include <vector>
      
      
      
      class myType {
         int a[10]{};
      public:
         auto begin() const {
             return a;
         }
         auto end() const {
             return a+10;
         }
         auto insert(const int*,int b) {
             a[0]+=b;
             return a;
         }
      };
      
      
      template<typename T>
      auto my_cbegin(const T& t) 
         -> decltype(std::begin(t)) {
             return std::begin(t);
      }
      template<typename T>
      auto my_cend(const T& t) 
         -> decltype(std::end(t)) {
             return std::end(t);
      }
      
      template<typename Container,typename T = typename Container::value_type>
      void insert(Container && years,T val) {
         auto iter = std::find(my_cbegin(years),my_cend(years),val);
         years.insert(iter,1998);
         for(auto i = my_cbegin(years); i != my_cend(years);i++) {
             std::cout << *i << std::endl;
         }
      }
      
      int main() {
         // std::vector<int> t{1983};
         // insert(t,1);
         myType t;
         insert(t,1);
      }
      
      
  5. 总结

    • c++11建议不修改都用const迭代器.

    • c++14的插入删除支持const和非const两种.

    • c++98的时候条件不好,支持不好,c++11也不太好,不过勉强够用.c++14较为完善.

    • 总是建议使用const迭代器.降低错误风险.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值