for循环的效率

时间:2012-08-08 13:30:08

标签: c++ performance for-loop

我需要堆栈溢出的意见来解决一直关注循环效率的问题。现在,当我开始编程时,“让它工作”是一个重中之重,我的大多数for循环都是这样的。

for (int i = 0; i < N; i++) {;}

然后我就开始了,特别是在C ++开发中,预增量会为你节省一些电话,并且考虑到这将是N次调用,并且它不会改变我养成习惯的可读性。

for (int i = 0; i < N; ++i) {;}

这已经足够好了一段时间,但专注于可读性,在阅读了Steve McConnell撰写的一些Code Complete之后,我到了这里。

for (int loop_index = 0; loop_index < loop_count; ++loop_index) {;}

这些变量会根据代码的上下文而改变。然后我读了一些关于内置类型构造函数和赋值的Effective C ++。而且基本上就是

之间的区别
int i = 42;

int i(42); 

是前者调用构造函数和赋值运算符,而后者只调用构造函数。所以我在编码的过程中将其纳入了常规。所以我的问题是,这是编写for循环最有效和最易读的方法:

for (int loop_index(0); loop_index < loop_counter; ++loop_index) {;}

6 个答案:

答案 0 :(得分:5)

实际上,

for (int i = 0; i < N; i++) {;}

很好。 iint,因此编译器无论如何都会优化后增量。是否使用intint i(42);初始化int i = 42;也是一个品味问题。

我也会调用迭代器i,而不是loop_index。前者无处不在,而后者则很奇怪。

但是,如果您正在处理迭代器,则图片会发生变化。机会it++仍然会优化到++it,但在这里,我宁愿使用预增量。

答案 1 :(得分:2)

如果你没有使用迭代器,那应该没关系,因为编译器会将它转换为相同的代码。

附录:如果您正在使用迭代器:

for(vector<int>::iterator i = a.begin(); i != a.end(); ++i)

然后++ i是i.operator ++()而i ++是i.operator ++(int),这可能意味着两件事。

顺便说一句。如果这是一个问题,您可以测量性能。

答案 2 :(得分:2)

首先,你的最后一点是不正确的。这一行

int i = 42;

复制初始化(请参阅此相关GoTW)。那里没有任务。如需作业,您需要

int i;
i = 42;

其次,在处理整数类型等内置函数时,编译器生成的代码可能没有区别。您应该分析不同的选项并查看。

答案 3 :(得分:1)

如果您使用的是内置类型或大多数迭代器,则所有这些都将编译为相同的代码。

所以我坚持用C ++最习惯的那个。

for (int i = 0; i < N; ++i) {;}

或者如果你想要罗嗦(但我和k传统上是循环索引)

for (int loop_index = 0; loop_index < loop_count; ++loop_index) {;}

作为我最初声明的证据:这两段代码生成相同的汇编代码。 (使用g++ -Os -S test.cpp编译的OS X上的g ++ 4.0.1)

void f(int); // So that smart compilers can't optimise away the loop entirely.

void g()
{
  int N=100;
  // for( int i=0; i<N; i++)
  for (int i(0); i < N; ++i) 
  {
    f(i);
  }
}

为完整起见,生成的代码为:

.globl __Z1gv
__Z1gv:
LFB2:
    pushl   %ebp
LCFI0:
    movl    %esp, %ebp
LCFI1:
    pushl   %esi
LCFI2:
    xorl    %esi, %esi
    subl    $20, %esp
LCFI3:
L2:
    movl    %esi, (%esp)
    incl    %esi
    call    L__Z1fi$stub
    cmpl    $100, %esi
    jne L2
    addl    $20, %esp
    popl    %esi
    leave
    ret

答案 4 :(得分:0)

虽然其他人已经很好地涵盖了后期与预增量和初始化,但我想补充一点,在大多数情况下使用int iint loop_index更具可读性,因为其他人都是使用和期待。

当你有多个循环,以及循环索引之间复杂的交互时,你可能想要调用它的唯一情况。例如

for (int row = 0; row < rows; row++) {
    for (int column = 0; column < columns; column++) {
        stuff[row * columns + column] = calc_stuff(row, column);
    }
}

答案 5 :(得分:0)

高效?不,它很可能是相同的,因为大多数编译器将优化int和简单指针的后增量和初始化。至于loop_index是否比i,IMO更具可读性,它对简单计数器的可读性较差。

如果它是一个迭代器,那就是不同的故事,编译器不能总是优化重载的后增量或迭代器的双重初始化。我也更喜欢将迭代对象的名称用于迭代器,因为它反映了更好地使用的内容,使用对象的名称在使用箭头时看起来更自然 - &gt;运算符取消引用迭代器。