在循环中声明变量是否有任何开销?(C++)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/982963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there any overhead to declaring a variable within a loop? (C++)
提问by laalto
I am just wondering if there would be any loss of speed or efficiency if you did something like this:
我只是想知道如果你做这样的事情是否会降低速度或效率:
int i = 0;
while(i < 100)
{
int var = 4;
i++;
}
which declares int var
one hundred times. It seems to me like there would be, but I'm not sure. would it be more practical/faster to do this instead:
声明int var
一百次。在我看来好像会有,但我不确定。这样做会更实用/更快吗:
int i = 0;
int var;
while(i < 100)
{
var = 4;
i++;
}
or are they the same, speedwise and efficiency-wise?
或者它们在速度和效率方面是否相同?
回答by laalto
Stack space for local variables is usually allocated in function scope. So no stack pointer adjustment happens inside the loop, just assigning 4 to var
. Therefore these two snippets have the same overhead.
局部变量的堆栈空间通常在函数范围内分配。所以循环内部不会发生堆栈指针调整,只是将 4 分配给var
. 因此,这两个片段具有相同的开销。
回答by Adam Rosenfield
For primitive types and POD types, it makes no difference. The compiler will allocate the stack space for the variable at the beginning of the function and deallocate it when the function returns in both cases.
对于原始类型和 POD 类型,它没有区别。在这两种情况下,编译器都会在函数开始时为变量分配堆栈空间,并在函数返回时释放它。
For non-POD class types that have non-trivial constructors, it WILL make a difference -- in that case, putting the variable outside the loop will only call the constructor and destructor once and the assignment operator each iteration, whereas putting it inside the loop will call the constructor and destructor for every iteration of the loop. Depending on what the class' constructor, destructor, and assignment operator do, this may or may not be desirable.
对于具有非平凡构造函数的非 POD 类类型,它会有所作为——在这种情况下,将变量放在循环外只会调用一次构造函数和析构函数,每次迭代只会调用赋值运算符,而将它放在循环之外循环将为循环的每次迭代调用构造函数和析构函数。根据类的构造函数、析构函数和赋值运算符的作用,这可能是也可能不是可取的。
回答by Alex Brown
They are both the same, and here's how you can find out, by looking at what the compiler does (even without optimisation set to high):
它们都是相同的,以下是您可以通过查看编译器的功能(即使没有将优化设置为高)来找出答案的方法:
Look at what the compiler (gcc 4.0) does to your simple examples:
看看编译器 (gcc 4.0) 对你的简单示例做了什么:
1.c:
1.c:
main(){ int var; while(int i < 100) { var = 4; } }
gcc -S 1.c
gcc -S 1.c
1.s:
1.s:
_main:
pushl %ebp
movl %esp, %ebp
subl , %esp
movl main() { while(int i < 100) { int var = 4; } }
, -16(%ebp)
jmp L2
L3:
movl , -12(%ebp)
L2:
cmpl , -16(%ebp)
jle L3
leave
ret
2.c
2.c
_main:
pushl %ebp
movl %esp, %ebp
subl , %esp
movl subl , %esp
, -16(%ebp)
jmp L2
L3:
movl , -12(%ebp)
L2:
cmpl , -16(%ebp)
jle L3
leave
ret
gcc -S 2.c
gcc -S 2.c
2.s:
2.s:
L3:
movl , -12(%ebp)
L2:
cmpl , -16(%ebp)
jle L3
From these, you can see two things: firstly, the code is the same in both.
从这些中,您可以看到两件事:首先,两者的代码相同。
Secondly, the storage for var is allocated outside the loop:
其次,var 的存储在循环外分配:
while (i< 100) {
LockMgr lock( myCriticalSection); // acquires a critical section at start of
// each loop iteration
// do stuff...
} // critical section is released at end of each loop iteration
And finally the only thing in the loop is the assignment and condition check:
最后,循环中唯一的事情是赋值和条件检查:
LockMgr lock( myCriticalSection);
while (i< 100) {
// do stuff...
}
Which is about as efficient as you can be without removing the loop entirely.
在不完全删除循环的情况下,这与您的效率差不多。
回答by Joshua
These days it is better to declare it inside the loop unless it is a constant as the compiler will be able to better optimize the code (reducing variable scope).
现在最好在循环中声明它,除非它是一个常量,因为编译器将能够更好地优化代码(减少变量范围)。
EDIT: This answer is mostly obsolete now. With the rise of post-classical compilers, the cases where the compiler can't figure it out are getting rare. I can still construct them but most people would classify the construction as bad code.
编辑:这个答案现在大部分已经过时了。随着后经典编译器的兴起,编译器无法解决的情况越来越少。我仍然可以构造它们,但大多数人会将构造归类为不良代码。
回答by Andrew Hare
Most modern compilers will optimize this for you. That being said I would use your first example as I find it more readable.
大多数现代编译器都会为您优化这一点。话虽如此,我会使用您的第一个示例,因为我发现它更具可读性。
回答by Michael Burr
For a built-in type there will likely be no difference between the 2 styles (probably right down to the generated code).
对于内置类型,两种样式之间可能没有区别(可能直接到生成的代码)。
However, if the variable is a class with a non-trivial constructor/destructor there could well be a major difference in runtime cost. I'd generally scope the variable to inside the loop (to keep the scope as small as possible), but if that turns out to have a perf impact I'd look to moving the class variable outside the loop's scope. However, doing that needs some additional analysis as the semantics of the ode path may change, so this can only be done if the sematics permit it.
但是,如果变量是一个具有非平凡构造函数/析构函数的类,那么运行时成本很可能会有很大差异。我通常会将变量范围限定在循环内(以保持范围尽可能小),但如果结果证明这对性能有影响,我会考虑将类变量移到循环范围之外。然而,这样做需要一些额外的分析,因为 ode 路径的语义可能会改变,所以这只能在语义允许的情况下完成。
An RAII class might need this behavior. For example, a class that manages file access lifetime might need to be created and destroyed on each loop iteration to manage the file access properly.
RAII 类可能需要这种行为。例如,可能需要在每次循环迭代中创建和销毁管理文件访问生命周期的类,以正确管理文件访问。
Suppose you have a LockMgr
class that acquires a critical section when it's constructed and releases it when destroyed:
假设您有一个LockMgr
类在构造时获取临界区并在销毁时释放它:
#include <stdio.h>
int main()
{
for(int i = 0; i < 10; i++)
{
int test;
if(i == 0)
test = 100;
printf("%d\n", test);
}
}
is quite different from:
与以下完全不同:
##代码##回答by Larry Watanabe
Both loops have the same efficiency. They will both take an infinite amount of time :) It may be a good idea to increment i inside the loops.
两个循环具有相同的效率。它们都将花费无限量的时间:) 在循环内增加 i 可能是一个好主意。
回答by user3864776
I once ran some perfomance tests, and to my surprise, found that case 1 was actually faster! I suppose this may be because declaring the variable inside the loop reduces its scope, so it gets free'd earlier. However, that was a long time ago, on a very old compiler. Im sure modern compilers do a better job of optimizing away the diferences, but it still doesn't hurt to keep your variable scope as short as possible.
我曾经运行过一些性能测试,令我惊讶的是,发现案例 1 实际上更快!我想这可能是因为在循环内声明变量会减少它的范围,所以它更早被释放。然而,那是很久以前,在一个非常旧的编译器上。我确信现代编译器在优化差异方面做得更好,但保持变量范围尽可能短仍然没有坏处。
回答by Byeonggon Lee
Code above always prints 100 10 times which means local variable inside loop is only allocated once per each function call.
上面的代码总是打印 100 10 次,这意味着每个函数调用只分配一次循环内部的局部变量。
回答by Byeonggon Lee
The only way to be sure is to time them. But the difference, if there is one, will be microscopic, so you will need a mighty big timing loop.
唯一确定的方法是给它们计时。但是差异,如果有的话,将是微观的,所以你需要一个强大的定时循环。
More to the point, the first one is better style because it initializes the variable var, while the other one leaves it uninitialized. This and the guideline that one should define variables as near to their point of use as possible, means that the first form should normally be preferred.
更重要的是,第一个是更好的风格,因为它初始化了变量 var,而另一个让它未初始化。这一点以及应该在尽可能靠近其使用点的地方定义变量的准则意味着通常应该首选第一种形式。