简体   繁体   English

iterator vs reverse_iterator

[英]iterator vs reverse_iterator

I'm using std::map to store a lot of elements (pairs of elements) and I have a "little" doubt. 我正在使用std::map来存储很多元素(元素对),我有一点“怀疑”。 What is more efficient to iterate all elements over my std::map , iterator or reverse_iterator ? std::mapiteratorreverse_iterator上迭代所有元素的效率更高?

For the record, dereferencing reverse_iterator on std::map and std::set containers is twice as slow as using iterator -- with both -O3 gcc 3.4.6 and MSVC on Intel/AMD processors (almost 3x as slow on PPC architectures.) Same holds for const_reverse_iterator vs. const_iterator . 对于记录,在std::mapstd::set容器上解除引用reverse_iterator 速度是使用iterator 两倍 - 在Intel / AMD处理器上同时使用-O3 gcc 3.4.6和MSVC(在PPC体系结构上几乎是3倍。 )同样适用于const_reverse_iteratorconst_iterator This is due to the fact that reverse_iterator actually points to the tree node immediately following the tree node to be dereferenced, hence the extra work. 这是因为reverse_iterator 实际上指向树节点后面的树节点被解除引用,因此额外的工作。 std::vector iterators exhibit a much milder difference ( reverse_iterator is only ~30% slower on PPC, virtually indistinguishable on Intel/AMD.) Incidentally, a std::vector iterator is about 20x faster than a std::map or std::set iterator. std::vector迭代器表现出更温和的差异(在PPC上, reverse_iterator只慢约30%,在Intel / AMD上几乎无法区分。)顺便说一句, std::vector迭代器比std::mapstd::set快约20倍std::set迭代器。

#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;
}

Does it really matter? 真的有关系吗? these are the types of the micro optimizations you must try to avoid IMHO. 这些是您必须尝试避免恕我直言的微优化的类型。 Also, even if the iteration time changes for very large number of elements in the map, the fact that you are trying to iterate through all the elements of such a big map means that most probably you have chosen a wrong data structure. 此外,即使迭代时间因地图中的大量元素而发生变化,您尝试迭代这样一个大地图的所有元素这一事实意味着您很可能选择了错误的数据结构。

Unless you have profiled your code and found there to be a significant difference, I just wouldn't be concerned about it. 除非你已经对你的代码进行了分析并发现它们存在重大差异,否则我就不会担心它了。

"Premature optimization is the root of all evil." “过早优化是万恶之源。” - Donald Knuth - 唐纳德克努特

There will likely be no difference. 可能没有区别。 std::reverse_iterator is just a template shim that translates ++'s to --'s at compile time. std :: reverse_iterator只是一个模板填充程序,可以在编译时将++转换为 - 。

For a vector or other contiguous storage container, a forward iterator might interact very slightly better with the cache than a reverse iterator would (unlikely you'd be able to detect it), but for a tree-based container it won't make any difference at all--there won't be any locality of reference to exploit. 对于向量或其他连续的存储容器,正向迭代器可能与高速缓存相比与反向迭代器相比会更好地交互(不太可能你能够检测到它),但对于基于树的容器,它不会产生任何完全不同 - 没有任何可供参考的地方。

Me think it does not make sense to use a reverse_iterator; 我认为使用reverse_iterator是没有意义的; it's counter intuitive. 这是反直觉的。

It would make the code harder to understand, someone will look at the code and go "wtf"; 它会使代码更难理解,有人会查看代码并转到“wtf”; and if you need to put a comment to explain why, it probably means it's not good code to start with. 如果你需要发表评论来解释原因,这可能意味着它不是一个好的代码。

I am wondering the need for iteration. 我想知道迭代的必要性。 Map holds the key-value pairs and normally you use it for the lookup. Map包含键值对,通常用于查找。 If you still need to iterate the map for some reasons ( may be deleting pointers contained inside the map etc) then you can use std::for_each . 如果由于某些原因仍然需要迭代地图(可能是删除地图中包含的指针等),那么你可以使用std :: for_each Forget the micro optimizations and you can try to increase the code readability. 忘记微优化,您可以尝试提高代码的可读性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM