【问题标题】:iterator vs reverse_iterator迭代器与反向迭代器
【发布时间】:2010-10-27 17:14:04
【问题描述】:

我使用std::map 来存储很多元素(元素对),但我有一个“小”疑问。在我的 std::mapiteratorreverse_iterator 上迭代所有元素更有效?

【问题讨论】:

    标签: c++ performance stl stdmap


    【解决方案1】:

    真的很重要吗?这些是您必须尽量避免恕我直言的微优化类型。此外,即使地图中大量元素的迭代时间发生变化,您尝试迭代如此大地图的所有元素这一事实也意味着您很可能选择了错误的数据结构。

    【讨论】:

    • 嗯,你是对的。我想将带有运算符“
    【解决方案2】:

    除非您分析了您的代码并发现存在显着差异,否则我不会担心它。

    “过早的优化是 都是邪恶的。”——唐纳德·高德纳

    【讨论】:

      【解决方案3】:

      可能没有区别。 std::reverse_iterator 只是一个模板 shim,它在编译时将 ++'s 转换为 --'s。

      对于向量或其他连续存储容器,前向迭代器与缓存的交互可能比反向迭代器稍微好一点(您不太可能检测到它),但对于基于树的容器,它不会'根本没有任何区别——不会有任何可利用的参考位置。

      【讨论】:

      • 不正确,它不仅仅是一个模板填充程序。仅供参考,set/map reverse_iterators 比正向迭代器慢 2 到 3 倍。
      【解决方案4】:

      我认为使用 reverse_iterator 没有意义;这是反直觉的。

      这会使代码更难理解,有人会看代码然后“wtf”;如果您需要发表评论来解释原因,这可能意味着它不是一开始的好代码。

      【讨论】:

        【解决方案5】:

        我想知道是否需要迭代。 Map 包含键值对,通常您将其用于查找。如果您由于某些原因仍需要迭代地图(可能是删除地图中包含的指针等),那么您可以使用std::for_each。忘记微优化,你可以尝试增加代码的可读性。

        【讨论】:

        • 首先,我没有-1你,但std::map被设计为可迭代的,如果你只使用键值对,你可能会使用像std::unordered_map这样的哈希映射.如果您需要键值和有序迭代,则使用 std::map 非常好。
        【解决方案6】:

        郑重声明,在 std::mapstd::set 容器上取消引用 reverse_iterator 比使用 iterator两倍 -- 同时使用 -O3 gcc Intel/AMD 处理器上的 3.4.6 和 MSVC(在 PPC 架构上几乎是慢 3 倍。)const_reverse_iteratorconst_iterator 相同。这是因为reverse_iterator 实际上 指向紧跟在要取消引用的树节点之后的树节点,因此需要额外的工作。 std::vector 迭代器表现出更温和的差异(reverse_iterator 在 PPC 上仅慢约 30%,在 Intel/AMD 上几乎无法区分。)顺便提一下,std::vector 迭代器比 std::mapstd::set 快约 20 倍迭代器。

        #include <set>
        #include <vector>
        #include <stdio.h>
        #ifdef _WIN32
        #include <sys/timeb.h>
        #else
        #include <sys/time.h>
        #endif
        #include <time.h>
        
        #define CONTAINER std::set< int >
        
        double
        mygettime(void) {
        # ifdef _WIN32
          struct _timeb tb;
          _ftime(&tb);
          return (double)tb.time + (0.001 * (double)tb.millitm);
        # else
          struct timeval tv;
          if(gettimeofday(&tv, 0) < 0) {
            perror("oops");
          }
          return (double)tv.tv_sec + (0.000001 * (double)tv.tv_usec);
        # endif
        }
        
        
        int main() {
          int i, x = 0;
          CONTAINER bla;
          for (i = 0; i < 10000; bla.insert(bla.end(), i++)) ;
        
          double t1 = mygettime();
        
          for (i = 0; i < 100; ++i) {
            for (CONTAINER::iterator it = bla.begin(); it != bla.end(); ++it) {
              x ^= *it;
            }
          }
        
          printf("forward: %f\n", mygettime() - t1);
        
          double t2 = mygettime();
        
          for (i = 0; i < 100; ++i) {
            for (CONTAINER::reverse_iterator it = bla.rbegin(); it != bla.rend(); ++it) {
              x ^= *it;
            }
          }
        
          printf("reverse: %f\n", mygettime() - t2);
        
          return 0;
        }
        

        【讨论】:

        • 投票赞成回答提出的问题。一些微优化是如此明显,以至于不实施它们应该被认为是糟糕的编程实践/错误......但我在性能关键领域工作;如果由我决定,C++ 将重命名为“++C”。
        • 这个答案比上面那个好。为什么它没有被选为正确的?另外,我很好奇如何在rb-tree中实现反向迭代器?
        猜你喜欢
        • 2012-05-09
        • 2013-02-07
        • 2016-10-22
        • 1970-01-01
        • 1970-01-01
        • 2020-01-21
        • 1970-01-01
        • 2015-11-07
        • 2018-09-23
        相关资源
        最近更新 更多