Ale*_*ecs 2 c++ indexing iterator stl stdvector
当使用std :: 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;
}
Run Code Online (Sandbox Code Playgroud)
调试模式:
没有优化结果
Result for iterator: 143
Result for index: 5
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 1000;
Result for iterator: 0
Result for index: 0
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 10000;
Result for iterator: 15
Result for index: 2
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 1000000;
Result for iterator: 1377
Result for index: 53
Run Code Online (Sandbox Code Playgroud)
带/ O2标志
for const int SIZE = 10000;
Result for iterator: 0 - 2
Result for index: 0
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 100000;
Result for iterator: 12 - 15
Result for index: 0
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 1000000;
Result for iterator: 133 - 142
Result for index: 0 - 3
Run Code Online (Sandbox Code Playgroud)
所以最好总是使用带向量的索引?
更新:
发布模式
使用/ O2标志,所有结果都为0.
禁用优化时/ Od索引更快
for const int SIZE = 100000000;
Result for iterator: 2182
Result for index: 472
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 1000000;
Result for iterator: 22
Result for index: 5
Run Code Online (Sandbox Code Playgroud)
for const int SIZE = 100000;
Result for iterator: 2 - 3
Result for index: 0 - 1
Run Code Online (Sandbox Code Playgroud)
第一件事是你应该使用任何惯用的用例.如果你正在迭代我会使用迭代器,如果你正在执行随机访问,那么索引.
现在来看实际问题.性能很难,即使测量性能也是一个难题,它要求您清楚地了解要测量的内容,测量方式以及不同的测试结果.理想情况下,您希望隔离测试以使测量尽可能精确,然后多次运行测试以验证结果是否一致.除了完全优化的代码之外,您甚至不应该考虑使用真正的程序来测量性能.如果您处于调试模式且程序很慢,那么最佳优化只是在发布模式下进行编译,增加优化级别,减少库中的调试结构.所有这些改进都是免费的.
在你的测试中,有太多的未知数和变量实际上从中产生了任何东西.编译器标志和选项可以产生很大的影响,因此学习如何使编译器生成更快的代码.向量的迭代器的简单实现是普通指针,因此您可以使用它来获得基本测量:
int *it=&v[0], *end=it+v.size();
for (; it!=end; ++it) temp=*it;
Run Code Online (Sandbox Code Playgroud)
这应该为您提供一个比较您的迭代器的基线.迭代器和此基线之间的性能差异是由于编译器/库供应商用于调试的额外检查.阅读有关如何禁用它们的文档.还要注意你的step(it++)需要it在指针的情况下创建一个基本上没有效果的副本,但如果迭代器完全保持任何状态,那么代价it++将占据整个循环.总是喜欢++it.
接下来是您要测量的内容以及编译器认为您需要的内容.您希望测量迭代,但编译器不知道它,它只看到您的代码,优化器将尽最大努力生成尽可能快的等效代码.只取一个循环,编译器可以意识到整个迭代除了设置temp之外没有任何副作用v[v.size()-1],在最坏的情况下(对于你的测量)它实际上可以执行转换,完全去除循环,这导致我们下一点:
细节决定成败.我的猜测是你的意图是在一般情况下测量迭代的相对成本,但是你的程序正在测量迭代恒定大小的向量的成本.为什么这很重要?编译器执行循环展开以避免测试成本.如果编译器知道您的循环将始终包含多个X迭代,那么它只能在每个X步骤中的一个步骤中测试循环完成.优化不能得到保证,在应用程序的一般情况下,编译器不会知道迭代次数,因此您应该确保测试不会为编译器提供比实际程序更多的优化机会.在这两种情况下,您希望确保编译器没有在实际情况下不具备的额外信息,也就是说,您希望隐藏测试知识并强制它专注于问题.我建议你将循环移动到不同的转换单元中的函数,通过引用传递向量,并确保它不能避免循环(将整数作为参数并使用临时和每个元素应用二元运算符在向量中,将所有操作的结果返回给调用者;在处理该函数时,编译器将无法做任何太聪明的事情)
但最重要的是,我必须将你引回到第一段,做什么是惯用的.编译器针对惯用代码进行了优化,并且当需要性能时,它们将做正确的事情.在这个答案,或在问题中的两个循环回路的性能是在一个优化的建立选中迭代器一样,不就是迭代本身的成本通常会在你的应用程序的性能在所有产生任何影响.