如果有一个名为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 ++。
答案 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
绝对运行时间是我用作比较指标的。 缓存条件比评估条件要一致(但略有改善)。