C ++:array.size()是循环的一个好条件吗?

时间:2012-04-30 10:00:08

标签: c++ caching for-loop

如果有一个名为arr的向量包含大量数据,我将打印该向量中的所有值。我会使用:

int arr_size = arr.size();
for(int i=0; i<arr_size; ++i) {//print the values}

或以这种方式实施:

for(int i=0; i<arr.size(); ++i) {//print the values}

在我看来,第一种实现方式是将向量的大小提取到缓存中,从而在第一次未命中后使条件更快。第二次实施怎么样?它慢了吗?每次满足条件时,系统是否会调用size()方法?

编辑:假设它正在使用C ++。

5 个答案:

答案 0 :(得分:6)

对具有arbirary body的循环进行推广,您给出的两个变体之间存在一个重要区别:如果arr的大小在循环期间发生变化会怎么样?

对于第二种情况,如果编译器可以假设它没有改变那么它可以优化循环,因此arr.size()只被调用一次,并且生成的代码变得与第一种情况大致相同。

但是如果循环体调用外部函数(极有可能)那么它就不能再做这个假设了,必须在每次循环迭代时检查arr.size()

虽然说arr.size()可能会对一个简单的结构成员访问有用,这个访问速度并不比将值存储在局部变量中慢,所以使用第一个变量没有太大的好处无论如何。除非arr是指针或引用,在这种情况下,它是间接的,然后是访问权限,因此第一个版本将是 litte 更快。

如果它是一个特别常见的运行循环,并且由于某种原因你必须在没有优化的情况下编译,你可能想要使用第一种情况来加速它。

但是那么,代码的可读性不会受到太多损害,因为它是一个额外的行吗?

总而言之,我会选择变体2,除非循环是一个必须紧密的内循环,在这种情况下我会选择变体1来确定。

当然,如果元素被添加到循环内的arr并且循环需要覆盖这些元素,那么只有第二个变体才是正确的。

答案 1 :(得分:4)

我建议你是否有可能使用迭代器而不是索引。 e.g:

在c ++中:

for( const_iterator it = arr.begin(), ite = arr.end();
     it != ite; ++it)
{
 ....
}

在c#中:

foreach(var item in arr){....}

c ++的一个优点是当你有list而不是vector时,vector size()是O(1)但是在列表中它是O(n)。这也可以防止多次调用arr.Size()的情况。

一般的优点是c#和c ++中的代码更易读,但仍有一些情况你不能使用它们,你应该使用索引。

答案 2 :(得分:1)

如果你有一个足够现代的编译器:

for (auto i: arr)
{
    //print the values
}

或者更好的是......避免滚动你自己的for - 循环(这也适用于预编译的C ++ 11编译器):

std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ","));

答案 3 :(得分:0)

第二种选择更好:

for(int i=0; i<arr.size(); ++i) {//print the values}

变量i将在循环结束后释放。 一旦循环初始化,将计算arr.size()。 内存不会分配给存储arr_size变量。

答案 4 :(得分:0)

我做了一些测试,缓存值似乎比每次迭代都更好地缓存条件。

这是我使用std::vector时的测试结果。

代码:Testing for-loop caching with std::vector 计时结果(4个运行用于评估运行和缓存运行):

Evaluated:
- Compilation time: 2,16 sec, absolute running time: 10,94 sec, absolute service time: 13,11 sec
- Compilation time: 1,76 sec, absolute running time: 9,98 sec, absolute service time: 11,75 sec
- Compilation time: 1,76 sec, absolute running time: 10,11 sec, absolute service time: 11,88 sec
- Compilation time: 1,91 sec, absolute running time: 10,62 sec, absolute service time: 12,53 sec

Cached:
 - Compilation time: 1,84 sec, absolute running time: 9,55 sec, absolute
   service time: 11,39 sec
 - Compilation time: 1,75 sec, absolute running
   time: 9,85 sec, absolute service time: 11,61 sec
 - Compilation time:
   1,83 sec, absolute running time: 9,41 sec, absolute service time:
   11,25 sec
 - Compilation time: 1,86 sec, absolute running time: 9,87
   sec, absolute service time: 11,73 sec

这是我使用std::list时的测试结果。

代码:Testing for-loop caching with std::list 计时结果(每个评估运行和缓存运行2次):

Evaluated:
 - Compilation time: 1,9 sec, absolute running time: 17,94 sec, absolute service time: 19,84 sec
 - Compilation time: 1,84 sec, absolute running time: 17,52 sec, absolute service time: 19,36 sec

Cached:
 - Compilation time: 1,81 sec, absolute running time: 17,74 sec, absolute service time: 19,56 sec
 - Compilation time: 1,92 sec, absolute running time: 17,29 sec, absolute service time: 19,22 sec

绝对运行时间是我用作比较指标的。 缓存条件比评估条件要一致(但略有改善)。