c++ - std::vector索引总是更快吗?

标签 c++ stl indexing iterator stdvector

使用std::vector时,通过索引遍历所有vector的元素总是比使用迭代器更快吗?

我写了简单的愚蠢测试,VS 2010,优化被禁用

#include <vector>
#include <iostream>
#include <ctime>

const int SIZE = 100000;    

int main()
{    
    std::vector<int> vInt;
    int i, temp;
    srand(time(0));
    for(i = 0; i<SIZE; i++)
        vInt.push_back(rand());

    time_t startTime, endTime;
    std::vector<int>::iterator it = vInt.begin(), itEnd = vInt.end();
startTime = clock();
for( ; it != itEnd; it++)
        temp = *it;
    endTime = clock();
    std::cout<<"Result for iterator: "<<endTime - startTime;

    i = 0;
    int size = vInt.size();
    startTime = clock();
    for(; i<size; i++)
        temp = vInt[i];
    endTime = clock();
    std::cout<<"\nResult for index: "<<endTime - startTime;    

    return 0;
}

Debug模式:

没有优化的结果是
Result for iterator: 143
Result for index: 5

对于const int SIZE = 1000;
Result for iterator: 0
Result for index: 0

对于const int SIZE = 10000;
Result for iterator: 15
Result for index: 2

对于const int SIZE = 1000000;
Result for iterator: 1377
Result for index: 53

带/ O2标志

对于const int SIZE = 10000;
Result for iterator: 0 - 2
Result for index: 0

对于const int SIZE = 100000;
Result for iterator: 12 - 15
Result for index: 0

对于const int SIZE = 1000000;
Result for iterator: 133 - 142
Result for index: 0 - 3

所以最好总是将索引与 vector 一起使用?

更新:

发行模式

使用 / O2标志时,所有结果均为0。

禁用优化时 / Od 索引更快

对于const int SIZE = 100000000;
Result for iterator: 2182
Result for index: 472

对于const int SIZE = 1000000;
Result for iterator: 22
Result for index: 5

对于const int SIZE = 100000;
Result for iterator: 2 - 3
Result for index: 0 - 1

最佳答案

第一件事是,对于您的用例,应该使用惯用的任何东西。如果要迭代,则使用迭代器,如果要执行随机访问,则使用索引。

现在到实际的问题。性能是很难的,即使衡量性能也是一个难题,它要求您对要衡量的内容,要如何衡量以及不同的事物如何影响测试有一个清晰的认识。理想情况下,您希望隔离测试以使测量尽可能精确,然后多次运行测试以验证结果是否一致。除了完全优化的代码之外,您甚至永远都不要考虑使用性能,最好是使用实际程序来衡量性能。如果您处于 Debug模式并且程序运行缓慢,则最佳的优化只是在 Release模式下进行编译,从而提高优化级别,从而减少库中的调试结构。所有这些改进都是免费提供的。

在您的测试中,有太多的未知数和变量无法实际使用它。编译器标志和选项可能会产生很大的影响,因此,请学习如何使您的编译器生成更快的代码。 vector 迭代器的一个简单实现是普通指针,因此您可以使用它来获得基本度量:

int *it=&v[0], *end=it+v.size();
for (; it!=end; ++it) temp=*it;

这应该为您提供一个与迭代器进行比较的基线。迭代器与该基准线之间的性能差异可能是由于编译器/库供应商用于调试的额外检查所致。阅读有关如何禁用它们的文档。还要注意,您的步骤(it++)需要创建it的一个副本,在这种情况下,指针基本上没有任何作用,但是如果迭代器完全保持任何状态,则it++的成本将主导整个循环。始终喜欢++it

接下来的事情是您要测量的内容以及编译器认为需要的内容。您想测量迭代,但是编译器却不知道,它只会看到您的代码,优化器将尽其所能来生成尽可能快的等效代码。仅使用其中一个循环,编译器就可以意识到,除了将temp设置为v[v.size()-1]之外,整个迭代都没有其他副作用,在最坏的情况下(对于您的测量),它实际上可以执行该转换,从而完全删除了循环,这导致了我们到下一点:

细节决定成败。我的猜测是,您的意图是在通常情况下测量迭代的相对成本,但是您的程序正在测量在恒定大小的 vector 上进行迭代的成本。为什么这么重要?编译器会尽一切可能进行循环展开以避免测试成本。如果编译器知道您的循环将始终包含X次迭代,那么它可以仅在每个X步之一中测试循环是否完成。不能保证优化,并且在应用程序的一般情况下,编译器将不知道迭代次数,因此您应确保测试不会为编译器提供比实际程序更多的优化机会。在这两种情况下,您要确保编译器没有它在实际情况下所没有的额外信息,也就是说,您要隐藏测试知识并迫使其专注于问题。我建议您将循环移到其他翻译单元中的函数中,通过引用传递 vector ,并确保避免循环(将整数作为参数,并对临时元素和每个元素应用二进制运算符在 vector 中,将所有操作的结果返回给调用者;在处理该函数时,希望编译器无法做任何太聪明的事情)

但最重要的是,我必须让您回到第一段,做些惯用法。编译器针​​对惯用代码进行了优化,当/如果需要性能时,它们将做正确的事情。此答案中的循环或问题中的两个循环的性能与优化构建中未经检查的迭代器相同,并不是说迭代本身的成本通常不会对应用程序的性能产生任何影响。

关于c++ - std::vector索引总是更快吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9735113/

相关文章:

c++ - C 数组 vs 指针 : array is considered as a variable, array+0 被认为是指针?

c++ - "Object reference not set to an instance of an object"弹出 Visual Studio 桌面

c++ - 如何使用 icc 编译器检查 gdb 中 std::vector 的内容?

algorithm - 计算数字组合的索引

mysql索引不能用

c++ - 外部联动

c++ - 恢复一个二元错位二叉搜索树

c++ - 我是否保证在 move vector 后指向 std::vector 元素的指针有效?

c++ - 基于 x 和 y 坐标排序

oracle - PL/SQL 匿名 block 与 PL/SQL 过程 - ORA-01418 : specified index does not exist