在循环之前或循环中声明变量之间的区别?

本文翻译自:Difference between declaring variables before or in loop?

I have always wondered if, in general, declaring a throw-away variable before a loop, as opposed to repeatedly inside the loop, makes any (performance) difference? 我一直想知道,一般而言,在循环之前声明一个抛弃型变量(而不是在循环内部重复)是否会产生(性能)差异? A (quite pointless) example in Java: Java中的一个(毫无意义的)示例:

a) declaration before loop: a)循环前声明:

double intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

b) declaration (repeatedly) inside loop: b)循环内的声明(反复):

for(int i=0; i < 1000; i++){
    double intermediateResult = i;
    System.out.println(intermediateResult);
}

Which one is better, a or b ? ab哪个更好?

I suspect that repeated variable declaration (example b ) creates more overhead in theory , but that compilers are smart enough so that it doesn't matter. 我怀疑重复的变量声明(示例b在理论上会产生更多开销,但是编译器足够聪明,因此无关紧要。 Example b has the advantage of being more compact and limiting the scope of the variable to where it is used. 示例b的优点是更紧凑,并将变量的范围限制在使用它的地方。 Still, I tend to code according example a . 尽管如此,我还是倾向于根据示例a进行编码。

Edit: I am especially interested in the Java case. 编辑:我对Java案例特别感兴趣。


#1楼

参考:https://stackoom.com/question/1hwd/在循环之前或循环中声明变量之间的区别


#2楼

There is a difference in C# if you are using the variable in a lambda, etc. But in general the compiler will basically do the same thing, assuming the variable is only used within the loop. 如果在lambda等中使用变量,则C#有所不同。但是通常,假定变量仅在循环内使用,编译器基本上会执行相同的操作。

Given that they are basically the same: Note that version b makes it much more obvious to readers that the variable isn't, and can't, be used after the loop. 鉴于它们基本上是相同的:请注意,版本b使读者更清楚地知道该变量在循环之后不能使用,也不能使用。 Additionally, version b is much more easily refactored. 此外, 版本b更易于重构。 It is more difficult to extract the loop body into its own method in version a. 在版本a中将循环体提取到其自己的方法中更加困难。 Moreover, version b assures you that there is no side effect to such a refactoring. 而且,版本b向您保证,这种重构没有副作用。

Hence, version a annoys me to no end, because there's no benefit to it and it makes it much more difficult to reason about the code... 因此,版本a无休止地困扰着我,因为它没有任何好处,并且使推理代码变得更加困难...


#3楼

The following is what I wrote and compiled in .NET. 以下是我在.NET中编写和编译的内容。

double r0;
for (int i = 0; i < 1000; i++) {
    r0 = i*i;
    Console.WriteLine(r0);
}

for (int j = 0; j < 1000; j++) {
    double r1 = j*j;
    Console.WriteLine(r1);
}

This is what I get from .NET Reflector when CIL is rendered back into code. 这是当CIL渲染回代码时从.NET Reflector中获得的。

for (int i = 0; i < 0x3e8; i++)
{
    double r0 = i * i;
    Console.WriteLine(r0);
}
for (int j = 0; j < 0x3e8; j++)
{
    double r1 = j * j;
    Console.WriteLine(r1);
}

So both look exactly same after compilation. 因此,两者在编译后看起来完全相同。 In managed languages code is converted into CL/byte code and at time of execution it's converted into machine language. 在托管语言中,代码将转换为CL /字节代码,并且在执行时将其转换为机器语言。 So in machine language a double may not even be created on the stack. 因此,在机器语言中,甚至可能不会在堆栈上创建一个double。 It may just be a register as code reflect that it is a temporary variable for WriteLine function. 它可能只是一个寄存器,因为代码反映它是WriteLine函数的临时变量。 There are a whole set optimization rules just for loops. 有整套针对循环的优化规则。 So the average guy shouldn't be worried about it, especially in managed languages. 因此,普通人不必为此担心,尤其是在托管语言中。 There are cases when you can optimize manage code, for example, if you have to concatenate a large number of strings using just string a; a+=anotherstring[i] 在某些情况下,您可以优化管理代码,例如,如果您必须仅使用string a; a+=anotherstring[i]连接大量string a; a+=anotherstring[i] string a; a+=anotherstring[i] vs using StringBuilder . string a; a+=anotherstring[i]与使用StringBuilder There is very big difference in performance between both. 两者之间的性能差异很大。 There are a lot of such cases where the compiler cannot optimize your code, because it cannot figure out what is intended in a bigger scope. 在很多情况下,编译器无法优化您的代码,因为它无法找出更大范围内的目标。 But it can pretty much optimize basic things for you. 但这可以为您优化基本的东西。


#4楼

I've always thought that if you declare your variables inside of your loop then you're wasting memory. 我一直以为,如果在循环内声明变量,那将浪费内存。 If you have something like this: 如果您有这样的事情:

for(;;) {
  Object o = new Object();
}

Then not only does the object need to be created for each iteration, but there needs to be a new reference allocated for each object. 然后,不仅需要为每个迭代创建对象,而且还需要为每个对象分配一个新的引用。 It seems that if the garbage collector is slow then you'll have a bunch of dangling references that need to be cleaned up. 看来,如果垃圾收集器运行缓慢,那么您将有一堆悬挂的引用需要清理。

However, if you have this: 但是,如果您有:

Object o;
for(;;) {
  o = new Object();
}

Then you're only creating a single reference and assigning a new object to it each time. 然后,您仅创建一个引用并每次为其分配一个新对象。 Sure, it might take a bit longer for it to go out of scope, but then there's only one dangling reference to deal with. 当然,超出范围可能会花费更长的时间,但是只有一个悬而未决的参考文献需要处理。


#5楼

My practice is following: 我的做法是:

  • if type of variable is simple (int, double, ...) I prefer variant b (inside). 如果变量的类型很简单(int,double,...),我更喜欢变量b (内部)。
    Reason: reducing scope of variable. 原因:减小变量的范围。

  • if type of variable is not simple (some kind of class or struct ) I prefer variant a (outside). 如果变量的类型不简单(某种classstruct ),我更喜欢变体a (外部)。
    Reason: reducing number of ctor-dtor calls. 原因:减少了ctor-dtor调用次数。


#6楼

A) is a safe bet than B).........Imagine if you are initializing structure in loop rather than 'int' or 'float' then what? 与B)相比,A)是一个安全的选择......想象一下,如果您正在循环中初始化结构而不是“ int”或“ float”,那又是什么?

like 喜欢

typedef struct loop_example{

JXTZ hi; // where JXTZ could be another type...say closed source lib 
         // you include in Makefile

}loop_example_struct;

//then....

int j = 0; // declare here or face c99 error if in loop - depends on compiler setting

for ( ;j++; )
{
   loop_example loop_object; // guess the result in memory heap?
}

You are certainly bound to face problems with memory leaks!. 您肯定会遇到内存泄漏的问题!。 Hence I believe 'A' is safer bet while 'B' is vulnerable to memory accumulation esp working close source libraries.You can check usinng 'Valgrind' Tool on Linux specifically sub tool 'Helgrind'. 因此,我相信“ A”是更安全的选择,而“ B”更容易受到内存累积的影响,尤其是在靠近源代码库的情况下。您可以检查Linux上的“ Valgrind”工具,特别是子工具“ Helgrind”。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值