通过迭代器和运算符[] / index快速访问std :: vector?

时间:2010-03-26 15:06:41

标签: c++ stl vector iterator performance

说,我有一个

std::vector<SomeClass *> v;

在我的代码中,我需要经常在程序中访问它们的元素,然后向前和向后循环它们。

这两者之间哪种访问方式最快?

迭代器访问:

std::vector<SomeClass *> v;
std::vector<SomeClass *>::iterator i;
std::vector<SomeClass *>::reverse_iterator j;

// i loops forward, j loops backward
for( i = v.begin(), j = v.rbegin(); i != v.end() && j != v.rend(); i++, j++ ){
    // some operations on v items
}

下标访问(按索引)

std::vector<SomeClass *> v;
unsigned int i, j, size = v.size();

// i loops forward, j loops backward
for( i = 0, j = size - 1; i < size && j >= 0; i++, j-- ){
    // some operations on v items
}

而且,如果我不需要修改它们,const_iterator是否提供了访问向量元素的更快方法?

11 个答案:

答案 0 :(得分:28)

性能差异可能是可忽略的或没有(编译器可能会将它们优化为相同);你应该担心其他事情,比如你的程序是否正确(一个缓慢但正确的程序比快速和错误的程序更好)。但是使用迭代器还有其他优点,例如能够在不修改循环的情况下将基础容器更改为没有operator[]的容器。有关详情,请参阅this question

与普通迭代器相比,

const_iterators很可能没有或可忽略的性能差异。它们旨在通过防止修改不应修改的内容而不是性能来提高程序的正确性。一般来说,const关键字也是如此。

简而言之,在发生两件事情之前,优化不应该是您的关注:1)您注意到它运行太慢和2)您已经描述了瓶颈。对于1),如果它比它运行慢十倍,但只运行一次并需要0.1ms,谁在乎呢?对于2),确保它肯定是瓶颈,否则优化它将对性能几乎没有可衡量的影响

答案 1 :(得分:17)

已经完成了一个简单的基于循环的基准测试。我使用了VS 2010 SP1(发布配置)。

  1. 使用迭代器(* it = * it + 1;)
  2. 使用指数(vs [i] = vs [i] + 1;)
  3. 在数十亿次迭代中,第二种方法的速度提高了1%。结果(索引比迭代器略快)是可重现的,但正如我所说,差异非常小。

答案 2 :(得分:6)

如果速度很重要,那么你应该有时间并且会在其上运行一个分析器,看看哪种情况最适合你的情况。

如果没关系,那么你正在进行过早优化,应该停止这样做。

答案 3 :(得分:3)

我相信向量迭代器在内部实现为指针(在良好的STL实现中),因此通常两个习语之间的性能差异应该可以忽略不计。但是如果你想知道这些在你的平台上的表现如何,为什么不用一点测试程序来测量呢?我认为测量执行时间不会超过5分钟。两种变体的100万次迭代......

答案 4 :(得分:2)

一如既往,这取决于。通常情况下,我不认为您会看到任何差异,但只有您可以通过分析您的代码来确定。有些编译器将矢量迭代器实现为原始指针,而有些编译器则不实现。此外,在调试版本中,某些编译器可能正在使用已检查的迭代器,这可能会更慢。但在生产模式下,它可能没有任何不同。简介并查看。

答案 5 :(得分:2)

我昨天进行了测试,使用[] vs iterator,代码创建了一个包含一些元素的向量,并从向量中删除了一些元素。 这是代码使用operator []访问元素

@echo off
set /a test = 4
IF %test% lss 10 (
@echo 0%test%
)
@pause

以下代码是关于使用迭代器

访问向量元素的
  TimeSpent([](){
    std::vector<int> vt = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    for (int i = int(vt.size()) - 1; i >= 0; i--)
    {
      if (vt[i] % 2 == 0)
      {
        //cout << "removing " << vt[i] << endl;
        vt.erase(vt.begin() + i);
      }
    }
  });

通过此功能单独调用

进行测试
  TimeSpent([](){
    std::vector<int> vt = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
    for (std::vector<int>::iterator num = vt.begin(); num != vt.end();)
    {
      if (*num % 2 == 0)
      {
        num = vt.erase(num);
      }
      else
      {
        ++num;
      }
    }
  });


经过测试的环境是visual studio 2013 pro。版本4.5.51650
结果是:
operator []:192
迭代器:212
总结:当我们访问向量容器时,operator []比迭代器更快。

答案 6 :(得分:1)

就速度而言,我认为可能几乎相同。 更好的是,无论如何你都可以进行剖析和检查。

至少可以减少使用的变量数量:)

for( i = 0; i < size ; i++){
    // some operations on v items
    v[i];
    v[size-i+1];
}

关于const_iterator:请参阅我的问:A re const_iterators faster ?

答案 7 :(得分:1)

我会选择迭代器,但我要优化的是在循环中调用end()并将preincrement更改为postincrement。即我最好

std::vector<SomeClass *> v;
std::vector<SomeClass *>::iterator i,ie;
std::vector<SomeClass *>::reverse_iterator j,je;

// i loops forward, j loops backward
for( i=v.begin(),ie=v.end(), j=v.rbegin(),je=v.rend(); i!=ie && j!=je; ++i,++j ){
    // some operations on v items
}

我不认为这是过早的微观优化,它只是编写更好的代码。比召唤每一次尝试编写有效的代码过早的微观优化并用思维来代替思考的情况要少得多。

答案 8 :(得分:1)

通过优化(-O2),时间应该改善(应该几乎相同)。

答案 9 :(得分:0)

您不仅要过早优化,还要进行微观优化。这是一种几乎与前者一样糟糕的邪恶(不同之处在于非常非常非常非常需要微观优化)。将两者放在一起,你就有了灾难的秘诀。

如果您运行探查器并发现此代码区域是瓶颈,那么您将需要进行优化。您不需要通过尝试将循环从23个时钟周期减少到22来进行优化。通过寻找减少算法的O()来优化。但是在你运行一个分析器之前,你应该比其他任何问题都更加关注设计。

答案 10 :(得分:0)

我对类似的东西感到困惑,并编写了一个程序来测试性能:https://github.com/rajatkhanduja/Benchmarks/blob/master/C%2B%2B/vectorVsArray.cpp

这是读取/写入向量&lt; int&gt;的相关观察结果。在Linux-i686(64位机器)上使用g ++(没有任何优化标志)的大小为1m,内存为7.7 GB: -

使用索引写入向量所花费的时间。 :11.3909 ms

按顺序使用索引从矢量读取所花费的时间。 :4.09106 ms

随机使用索引从向量读取的时间。 :39毫秒

使用迭代器(顺序)写入向量所花费的时间。 :24.9949 ms

使用迭代器从矢量读取的时间(顺序)。 :18.8049 ms