什么更快,用vector :: iterator或with()迭代STL向量?

Gal*_*man 57 c++ performance iterator stl vector

在性能方面,什么会更快?有区别吗?它是平台依赖的吗?

//1. Using vector<string>::iterator:
vector<string> vs = GetVector();

for(vector<string>::iterator it = vs.begin(); it != vs.end(); ++it)
{
   *it = "Am I faster?";
}

//2. Using size_t index:
for(size_t i = 0; i < vs.size(); ++i)
{
   //One option:
   vs.at(i) = "Am I faster?";
   //Another option:
   vs[i] = "Am I faster?";
}
Run Code Online (Sandbox Code Playgroud)

tst*_*ner 36

使用迭代器会导致递增指针(用于递增)和解除引用以取消引用指针.
对于索引,递增应该同样快,但查找元素涉及添加(数据指针+索引)和解除引用该指针,但差异应该是边际的.
at()还会检查索引是否在边界内,因此可能会更慢.

500M迭代的基准测试结果,矢量大小10,gcc 4.3.3(-O3),linux 2.6.29.1 x86_64
at():: 9158ms
operator[]:4269ms
iterator:3914ms

YMMV,但是如果使用索引使代码更易读/可理解,那么你应该这样做.

  • @Michael` at()`执行边界检查,所以它是`data [i]`vs`if(i <length)data [i]` (4认同)
  • -1抱歉.如果你看这里:http://www.velocityreviews.com/forums/showpost.php?p = 1502464&posttcount = 13,你会看到这个人**没有使用任何编译器优化标志**,所以结果基本上没有意义. (3认同)
  • +2现在您已经更新了更合理的测量标准:) (2认同)

小智 27

为什么不写一个测试并找出来?

编辑: 我的坏 - 我以为我是优化版本的计时但不是.在我的机器上,用g ++ -O2编译,迭代器版本比operator []版本略,但可能不是那么明显.

#include <vector>
#include <iostream>
#include <ctime>
using namespace std;

int main() {
    const int BIG = 20000000;
    vector <int> v;
    for ( int i = 0; i < BIG; i++ ) {
        v.push_back( i );
    }

    int now = time(0);
    cout << "start" << endl;
    int n = 0;
    for(vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
        n += *it;
    }

    cout << time(0) - now << endl;
    now = time(0);
    for(size_t i = 0; i < v.size(); ++i) {
        n += v[i];
    }
    cout << time(0) - now << endl;

    return n != 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 在我的测试中(使用"time"shell内置并且所有cout都被禁用,每次都注释掉一个测试)两个版本同样快速(更改代码使其在构造函​​数中分配,每个元素的值都为"2").实际上每次测试的时间变化大约10ms,我怀疑是因为内存分配的非确定性.有时一个,有时另一个测试比另一个快10ms. (5认同)
  • @anon:这不是关于更高的分辨率.它是关于使用`clock()`而不是`time()`来明确地忽略"在代码运行时可以在现代操作系统中进行的所有其他活动".`clock()`仅测量用于该进程的CPU时间. (4认同)
  • 每次循环时都要实例化结束迭代器,并且迭代器实例化不是免费的.尝试缓存您的结束迭代器.试试这个:`for(vector <int> :: iterator it = v.begin(),end = v.end(); it!= end; ++ it){...}` (4认同)
  • 您是否使用完全优化进行测试并首先尝试使用迭代器版本和首先使用阵列版本?性能可能略有差异但是2倍?不是机会. (3认同)

xto*_*ofl 15

如果您不需要索引,请不要使用它.迭代器概念是最好的.迭代器非常容易优化,而直接访问需要一些额外的知识.

索引用于直接访问.括号和at方法执行此操作. at将不会[]检查越界索引,因此它会更慢.

信条是:不要问你不需要什么.然后编译器不会向您收取您不使用的内容.


Jam*_*kin 14

既然您正在考虑效率,那么您应该意识到以下变化可能更有效:

//1. Using vector<string>::iterator:

vector<string> vs = GetVector();
for(vector<string>::iterator it = vs.begin(), end = vs.end(); it != end; ++it)
{
   //...
}

//2. Using size_t index:

vector<string> vs = GetVector();
for(size_t i = 0, size = vs.size(); i != size; ++i)
{
   //...
}
Run Code Online (Sandbox Code Playgroud)

因为end/size函数只调用一次而不是每次调用循环.编译器很可能无论如何都会内联这些函数,但这种方式可以确保.

  • @underscore_d是的.我不知道2年前我在想什么大声笑. (4认同)

Bri*_*ndy 5

我猜第一个变体更快。

但这取决于实施。为确保您应该分析您自己的代码。

为什么要分析自己的代码?

因为这些因素都会改变结果:

  • 哪个操作系统
  • 哪个编译器
  • 使用的是哪种 STL 实现
  • 是否开启了优化?
  • ...(其他因素)


Mat*_*son 5

正如这里的其他人所说,做基准测试.

话虽如此,我认为迭代器更快,因为at()也会进行范围检查,即如果索引超出范围,它会抛出一个out_of_range异常.检查本身可能会产生一些开销.