DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

+ Reply to Thread
Results 1 to 12 of 12
  1. #1
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604

    Performance impact of delaring variables inside loops

    Hi,

    We just had a discussion about the performance impact of declaring variables inside loop rather than in the for-init or outside the loop.

    [CODE]
    SomeType xxx;
    for(int i; i < iLength; i++)
    {
    // use xxx here
    }

    Code:
    for(int i; i < iLength; i++)
    {
    SomeType xxx; // will this be somehow optimized or will the object re-created
                         // every time the loop is entered?
    // use xxx here
    }
    Thanks for your input.

    Cheers,
    D
    DKyb
    -------------------------------
    Life is a short warm moment -
    Death is the long cold rest.
    Pink Floyd
    -------------------------------

  2. #2
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    found the answer myself (or probbly part of it) myself by running the following:
    Code:
    #include <iostream>
    #include <vector>
    using namespace std;
    class test
    {
    public:
        test() { cout << "test()" << endl; }
        ~test() { cout << "~test()" << endl; }
        void hello() { cout << "hello" << endl; }
    };
    int main()
    {
        int i;
        cout << "test declared inside the loop:" << endl;
        for(i= 0; i< 10 ; i++)
        {
            test t;
            t.hello();
        }
    
        cout << "now test declared outside the loop:" << endl;
        test t;
        for(i= 0; i< 10 ; i++)
        {
            t.hello();
        }
    
        return 0;
    }
    DKyb
    -------------------------------
    Life is a short warm moment -
    Death is the long cold rest.
    Pink Floyd
    -------------------------------

  3. #3
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Would still be interesting to know, whether more up-to-date compilers than VS6 can do some optimization say for native types in certain circumstances and whether the standard allows that...

  4. #4
    Join Date
    Nov 2003
    Posts
    4,118
    OF course, when using local automatic objects, the object is created and destroyed a new with each entrance into the block. That's why you have to think carefully about your design. For example, if the loop write a line of text to the same file, it makes no sense to declare the file stream object locally, because each iteration will construct a new stream object. In such cases, it's best to declare the object at an enclosing scope.
    However, there are obvious cases when you truly need a new object on each iteration. For example, when you need to create many small files with different names, it makes sense to represent each file as a local stream object created inside a loop, and be done with it when the current iteration ends.
    So this isn't truly a question of optimization or compiler's intelligence. It's a design choice that belongs to the programmer. BTW, programmers often forget that there is a third option: create a local static object that retains its state from one iteration to another while remaining unexposed to any outer scope.
    Danny Kalev

  5. #5
    Join Date
    Dec 2003
    Posts
    3,366
    its horrible when the object is a true variable (not static, not const, but actually requires a memory flush in and out and ctor/ etc (stack push or whatever this involves). Const object creation inside the loop can ENHANCE performance considerably in some cases(see below). Modern compilers are a little better but still noob this up badly more often than not. It is also a big hit on small functions called often. I would recommend static, but with multi processing the name of the game today, this can be unsafe as well! Much of my old code is going to need some static removal and algorithm tweaking to share processors... sigh

    for example

    for(outer loop; cond; whatever++)
    {
    stuff;
    const int x = someresult; //if he will be used a lot in the inner loop
    for(innerloop; othercond; morestuff)
    {
    use(x) + needs_x* x .. etc; // often much better than if x were a variable!
    }
    }

    I avoid the "for(int x = ...) style as it makes the code harder to read ( where did x come from, cant quickly locate it!) and you often create the same variable 3 or 4 times in a row (back to back for loops) and it can cause a performance hit over making the item at the routine start (this varies but if you put it at the start, its never a problem, would you rather test it on each and every compiler version?).


    Just my 2 cents. I know some say that putting it in the loop is more readable, some people like/force misaligned brackets too, such things are up to the readers.

  6. #6
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Hi jonnin,
    just a quick one: if you say
    const creation inside a loop can enhance performance
    do you mean const as opposed to non-const or inside loop as opposed to outside loop. Latter doesn't really sound right to me.

    For the sake of readability, I'd prefer to create all my variables outside the loops where possible (Danny's example I think is a sensible exception to that rule).

    I am no fan of the old C-style declaration block at the beginning of each function and think variables should be declared/defined close to where they are used.

    Although I am sometimes lazy, I have to agree with you on declarations on the for-init: I think it's better to declare iterators before the first loop because this way they can be re-used in multiple loops (especially when they are called "i" and "j"). And performance shouldn't an issue here, as the compiler should be able to optimise them.

    Cheers,

    D
    DKyb
    -------------------------------
    Life is a short warm moment -
    Death is the long cold rest.
    Pink Floyd
    -------------------------------

  7. #7
    Join Date
    Nov 2003
    Posts
    4,118
    I have to disagree about iterators declaration outside the loop. in-lop declarations cost you nothing and they are much safer. Why allow other loops to mistakenly use an iterator that may have been left with a value from a previous loop? Besides, if you're don of i and j, you can use these names as many time as you want as long as they are declared locally in each loop:

    for (int i=0;...)
    {
    }

    for(int i=5;...)
    {

    }

    When dealing with STL iterators, there's another issue here: some iterators are const_iterator others aren't. You certainly don't want to mix them and worse yet-- what guarantees do you have that these iterators still point to a valid element (or container!) when used by a second loop? Many things could have happened in between that may have invalidated the iterators. Remember: there was a huge demand and pressure for localizing for loop variables, and with reason. Take advantage of that and make your code safer. And if you're wary of the cumbersome syntax of iterator declarations, the revamped auto keyword will soon solve this problem too.
    Danny Kalev

  8. #8
    Join Date
    Nov 2003
    Posts
    4,118
    Quote Originally Posted by jonnin
    its horrible when the object is a true variable (not static, not const, but actually requires a memory flush in and out and ctor/ etc (stack push or whatever this involves).
    I have to disagree here. There's nothing horrible about recurrent construction and destruction of local objects, as long as this is what you really want. Remember that in some programming idioms, the destructor has side effects that release or finalize a certain resource (such as writing to a long file, closing a transaction etc.) In these cases you clearly want that each RAII object shall be destroyed separately and fast instead of reusing the same battered object over and over again. Of course, there are many other counter examples in which a single object should remain alive to minimize ctor dtor costs or simply because it's convenient. In that case, either use a local static object (if it's a single threaded app) or allocate the object dynamically and make sure that some smart pointer destroys it at the end of the program. What I'm trying to say here is that I don;t expect compilers to be psychic. If I need a local automatic object, I want to compiler to construct and destroy it anew because that's exactly what my design is based upon. If I don't want that, I will choose a different approach, but that's a programmer's choice, not a compiler's choice.
    Danny Kalev

  9. #9
    Join Date
    Dec 2003
    Posts
    3,366
    For the const inside the loop, the example should show what I meant to say. Its a nice way to make the inner loop run faster for certain operations, a "try it and see" sort of optimization. To restate it, values computed in an outer loop that are used a lot (but not modified) in an inner loop can improve performance if created with a "const type value = computation" in the outer loop.

    And Danny, from a performance standpoint I have found declare/destroy inside a loop to be a major performance hit unless there is a reason (dtor cleanup is a valid reason, of course! However it would still be more efficient (purely from a performance standpoint) to make a cleanup() method and declare the variable once outside the loop and call cleanup (or, better still, allow access to whatever needs to be reset to avoid function call overhead). Of course, this sort of thing is for real time code and usually does not matter at all for most code. Deep inside the tight loops, however, some OOP features still get in the way sometimes. Every compiler generation decreases these hits and every processor generation makes fewer sections of code need this sort of thing. I am finally finding that it just does not matter anymore most of the time (its coming down to only large (200X200 or larger) matrix operations are needing it instead of every calculation loop like it was 5 years ago). Almost all of the inline assembly is slipping out of my code as are totally public classes(direct access was faster than methods) etc. As you said, its the programmers choice (as it should be! thats why c++ is so powerful!). And when the speed is not a factor, that choice should be the most readable / useful / etc choice. I freely admit some of the things that I have had to do to meet time slices are unattractive & confusing, and am glad to see the hardware leaps of the past year so I can finally break free of rewriting the same loop 10 times... (NOT looking forward to removal of 20000 static variables so we can thread this stuff up)

    I have also found that the for(int i =...) does cost you a variable creation hit, however it only happens once for the duration of the loop (unlike for(..) {int i...} which is every iteration. Where it bites you is nested loops (esp that third deep one), the inner loop does a creation each time and this is a noticeable penalty on a tight loop, at least on this compiler. Hopefully this is optimized out on newer ones? It would be nice. I also have just a brain freeze every time I type this because it was broken for me for 2 years (visual 6) and it still is second nature to simply not do it this way.

    I do NOT do C definitions (all at the top) however I do prefer all the variables to be at the function scope (I rarely create them inside blocks inside functions, unless the inner block is relatively large). I do sometimes put i,j,k inside a class so I always have loop counters for iteration intense objects (again with the matrix stuff & its not going to work in multi threaded). None of that really matters much. Over the years I have found that the most important thing about style is that everyone on the project follows similar style & that all the code is consistent.

    Since its already a huge post...
    I am looking forward to making parallel algorithms & threaded apps (well they were threaded, but not on the scale expected with multi processors). Go parallel or perish? Definitely yes, in a world where space, battery power, and other resources used are basically cut in half (basically 2 computers using the resources of one!!!) it will cut costs or enhance capability for us at every turn. For the standard desktop/server, does every app have to be parallel or massively threaded? No, of course not. Just like optimizations, you can choose what is critical to thread (if anything) or where to develop parallel algorithms. Threading is "friendly" on such machines so your app does not hog resources (lets the OS do load balance), but for smallish tools this also will not matter.
    Last edited by jonnin; 03-08-2007 at 10:39 AM.

  10. #10
    Join Date
    Dec 2003
    Posts
    3,366
    I went back and timed a few things.
    On my new computer, a triple loop with the inner loop doing d = sqrt(rand())

    8.5 seconds no matter what. For loops with the int declared in them or before the loops, double d declared inside the loop or outside them, no real difference.

    Backing up to vs 6.0 both the double in the loop & the int in the for loop had an impact of over 1/10 a second. So it was an artifact of a very old compiler that I was remembering.

    Using a class with actions in the ctor and dtor instead of the double (class had a double member), creating the object each loop iteration cost a ton. It was 33 seconds total. Putting it outside the loops put it at 8.6. So this is the one case to be careful with!

    So the bottom line is vs 6 had a lasting impact on me, some of the things I remember as being slow no longer are. Which of course means that you should always time and profile a few versions of the code on YOUR system when times matter...

  11. #11
    Join Date
    Nov 2003
    Posts
    4,118
    I think I can endorse most of what you said. However, I want to clarify two things:
    the construction/destruction of local automatic objects that aren't declared const isn't exactky a compiler's choice. The standard requires that for an object with non trivial ctor and dtor, the ctor and dtor shall execute when the block is created/left, no matter what. Of course the compiler can use some tricks to optimize some cases but it can't just throw away the construction/destruction of a certain object just because they are local to a tight loop.
    As for deeply nested loops: here the compiler has more leeway. It can flatten the loop so the performance hit can be minimal.
    Danny Kalev

  12. #12
    Join Date
    Jan 2005
    Location
    UK
    Posts
    604
    Thanks for the input ol'chaps!
    Danny has a valid point with for-init declared variables, but I would say that that using them can make loops quite unreadable, say if you need to declare/define more than one in a loop.
    Code:
    for(int i= 0, bool found=false; i<someFancyMaximum && !found; i++)
    {/* ... */ }
    Here we got two variables, but potentially there could be more and commas look so similar to semicolons ;-)
    I think it would be nicer and more consistent to declare both of them outside the loop, but I guess that's more a matter of personal esthetics.
    I always found the for() - syntax in C/C++ a bit of a breach of syntax - consistency. Other languages seemed to be a bit more straight forward in their approach (E.g. PASCAL handles while and for loops very similarly).
    But thanks: the original question (performance) is very clearly answered.

    Cheers,
    D

Similar Threads

  1. Replies: 2
    Last Post: 03-02-2006, 02:40 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


Top DevX Stories

Easy Web Services with SQL Server 2005 HTTP Endpoints
JavaOne 2005: Java Platform Roadmap Focuses on Ease of Development, Sun Focuses on the "Free" in F.O.S.S.
Wed Yourself to UML with the Power of Associations
Microsoft to Add AJAX Capabilities to ASP.NET
IBM's Cloudscape Versus MySQL


Sponsored Links