views:

175

answers:

7
 std::vector<double> C(4);
 for(int i = 0; i < 1000;++i)
  for(int j = 0; j < 2000; ++j)
  {   
   C[0] = 1.0;
   C[1] = 1.0;
   C[2] = 1.0;
   C[3] = 1.0;
  }

is much faster than

 for(int i = 0; i < 1000;++i)
  for(int j = 0; j < 2000; ++j)
  {
   std::vector<double> C(4);
   C[0] = 1.0;
   C[1] = 1.0;
   C[2] = 1.0;
   C[3] = 1.0;
  }

I realize this happens because std::vector is repeatedly being created and instantiated in the loop, but I was under the impression this would be optimized away.

Is it completely wrong to keep variables local in a loop whenever possible? I was under the (perhaps false) impression that this would provide optimization opportunities for the compiler.

Or maybe that only applies to POD types and not something like std::vector.

EDIT: I used VC++2005 (release mode) with full optimization (/Ox) on Windows XP

A: 

The scope of the obj would be inside the loop, so you won't be able to use it once the loop(s) is(are) finished. This is in addition, to the object getting instantiated and then destroyed as many times as the loop(s) goes(go) through. In the end, nothing is accomplished except time is being wasted constructing and then destroying the object.

Khnle
+1  A: 

The second way is allocating new memory (in your case 1000*2000 times). Each one being a completely new memory location in heap (although not always new, can be in the same location). Memory allocation takes longer time than just modifying the values contained in already allocated memory.

The first way is allocating 1 memory location array, and just modifying the values in it. If compilers do optimize for this (which isn't always the case), better not leave it to the compiler, if you can choose to allocate less memory (or less often) yourself as a programmer.

Sev
+1  A: 

Creation of the vector is expensive, in this case, because it may allocate an array of size 4 on the heap.

If you know the size of the 'local' vector upfront, you may as well use an automatic array:

for( int i = 0; i != 2000; ++i ) {
   int C[4]; // no initialization
   C[0] = 1;
   // ...
}

This way you loose the cost of allocating free memory.

xtofl
A: 

First thing you should do is making sure that the design is OK, this means:

  • Is the code easy to understand
  • Does the code prevent itself against bugs
  • Is the code easily extensible

I think that in this case it would indeed imply that it's better to define the variable in the loop.

Only if you have real performance problems, you may optimize your code (if the compiler didn't already do this for you), e.g. by putting the variable declaration outside the loop.

Patrick
This *is* a real performance issue since I've profiled it.
Jacob
Then be free to put the variable outside the loop, but clearly comment in your code why you did, so the next developer doesn't put it back in the loop.
Patrick
+2  A: 

The problem is heap activity. Replace std::vector<double> C(4); with std::array<double, 4> C; and it should not make any difference where you place the variable anymore.

FredOverflow
Google says that std::array is C++0x
Dummy00001
then use boost, or a C-style array.
Pete Kirkham
Or `std::tr1::array` if you have a "halfway modern" compiler.
FredOverflow
+1  A: 

I was under the (perhaps false) impression that this would provide optimization opportunities for the compiler.

This is probably true for built-in types such as int or double.

The issue here is that you are using vector which needs to run the constructor on entering the loop body, and the destructor when leaving. Since both these methods are non-trivial the compiler cannot optimise these away, as your program would no longer be correct.

As a counter-examample for this, imagine what such an optimisation would do if you used a file object instead of a vector.

Hitobat
+2  A: 

Is it completely wrong to keep variables local in a loop whenever possible? I was under the (perhaps false) impression that this would provide optimization opportunities for the compiler.

No, that's a good rule of thumb. But it is only a rule of thumb. Minimizing the scope of a variable gives the compiler more freedom for register allocation and other optimizations, and at least as importantly, it generally yields more readable code. But it also depends on repeated creation/destruction being cheap, or being optimized away entirely. That is often the case... But not always.

So as you've discovered, sometimes it's a bad idea.

jalf
Thanks jalf, I suppose it's just a rule of thumb and I can't expect the almighty compiler to optimize things like `std::vector` away without profiling first.
Jacob
Some compilers might well be able to do it in some cases. And of course, in many other cases it just doesn't matter performance-wise. But not this time. :)
jalf