tags:

views:

171

answers:

6

Here is what I mean, suppose I have code like:

for (int i = 0; i < 1000; i++) {
    char* ptr = something;
    /*
    ... use ptr here
    */
}

It seems that char* ptr gets allocated every time in the loop, making it ineffective?

Is it more effective to write this?

char* ptr = something;
for (int i = 0; i < 1000; i++) {
    /*
    ... use ptr here
    */
}

Please comment on this interesting problem. Thank you!

Thanks, Boda Cydo.

+1  A: 

The way that code gets translated really depends on your compiler and the optimizations it performs. The compiler might perform a "dumb" translation and allocate every loop, or it might place the allocation outside the loop for you in it's optimization phase. To be safe, I would place the declaration outside the loop. As with anything, you could test out both and see how long each loop takes to see if there is a difference.

Scott M.
There's no "allocation" going on at point-of-declaration on any architecture I've ever encountered. Construction, initialization, and destruction, yes.
Ben Voigt
“to be safe …” – no. That’s exactly the wrong way round: a misleading pseudo-optimization. The right way is: until proof of the ineffectiveness emerges, use the semantically most meaningful form (i.e. place it inside the loop). *Only* if further knowledge shows that this is insufficient, act.
Konrad Rudolph
To my eye, if a variable is invariant to the loop, the most semantically meaningful form is to declare it outside the loop, thus showing that it isn't dependent on the body of the loop.
Joe Gauterin
I don't see how placing the declaration just outside the loop is any less meaningful. Yes, I can understand that the variable could be used deep inside the loop, but the point is you don't know the optimizations ahead of time unless you have profiled that type of code before or you have intimate knowledge of the compiler itself. So yes, I maintain my "To be safe" as a valid argument.
Scott M.
+12  A: 

It can make a performance difference, but many optimizing compilers undertake this optimization for you, if appropriate. This is called "loop-invariant code motion".

John the Statistician
A: 

You have to profile and see for yourself. Check out this question (and the accepted answer) of mine as a reference. As jalf says, it's just a rule of thumb to expect it to be optimized away (and it's probably correct for POD types) but you'll need to back it up with profiling.

Jacob
A: 

As a matter of personal convention in 'C' programs, I like to put variable declarations at the top of the function, top of the file or in a common .h file. If I start to bury declarations within the code it could potentially be confusing and easy to lose track of variable scope, resulting in unwanted consequences.

Edward Leno
That's not just a matter of personal convention, it's a requirement of C89/C90 that local variables be declared at the top of their scope.
Ben Voigt
There are SE arguments opining that variable declarations should be as close to their use as possible, so that the scope of the variable's use is clear in the code.
jdizzle
Agreed, with my 'personal convention' being that I like to put the declarations in these 3 areas specifically and try to stay away from putting declarations inside for/while loops. I try to make it a practice to have the 'inner most' declarations at the function level (unless there is a real good reason). Refactoring can help make this personal requirement easier to manage.
Edward Leno
I disagree. Variables should be declared in the smallest enclosing scope, to increase locality and restrict the scope as much as possible. If your scopes are large enough that this becomes confusing, other things are probably also confusing, and you should consider refactoring.
David Thornley
I am only using these 3 spots as a guideline. I do mention that by refactoring the functions should be small and do only 1 thing. This usually results in the smallest enclosing scope (there are always exceptions, but I use this as a rule of thumb).
Edward Leno
A: 

For built-in types such as the char* in your example, there isn't much difference. The second form is usable after the loop exits, and only evaluates the initializer once. But as John says, most compilers will precalculate the initialization anyway.

There's an obvious difference if ptr gets re-assigned inside the loop (and if you don't reassign it, you should make it char* const ptr), in that the value will be kept from the previous iteration instead of reset.

Finally, non-POD types would have their constructor and destructor run for every loop iteration.

Ben Voigt
+2  A: 

I'm of the school that thinks it's better to limit the scope of variable names as much as possible; if ptr isn't meant to be referenced outside of the loop, then it should not be declared outside of the loop.

However, if something turns out to be an expensive operation AND it's invariant (i.e., it doesn't depend on i) AND it's preventing your code from meeting a hard performance requirement, then yes, you should move the declaration outside of the loop.

This is unspeakably ugly, but you can do something like this:

do
{
  char *ptr = something;
  for (int i = 0; i < 1000; i++)
  {
    /* use ptr here */
  }
} while (0);

You're still limiting the scope of ptr, but you're no longer assigning it on every loop iteration.

John Bode
+1: but as an aside, you generally don't need the `do`/`while` keywords around the braces (or the trailing semi-colon) if you're coding this up yourself inline. Macros that need to introduce scope often use that construct so they don't cause surprises with various other bits of syntax (like causing syntax problems in if/else statements), but outside of a macro it's usually unnecessary (though it doesn't hurt, except that you might consider the keywords unnecessary clutter).
Michael Burr